diff --git a/DEPS b/DEPS index 9e72239..637af68 100644 --- a/DEPS +++ b/DEPS
@@ -39,11 +39,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'b988ecf639f1394ea5e821ac15b989e25e064534', + 'skia_revision': '09aa1fce69b214714171db12c341aebd78dd29ea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '0d3888a14530bfae7f76268e18e386016cf0ff40', + 'v8_revision': '05c1f97eaca1185948b99a17f598ff345ff577ca', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -51,11 +51,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'ae2d0a0e865545fbc5f55bf2014d00bb8f4669c9', + 'angle_revision': 'b0a531059e96765819c6230c6e8eb22a304bd2d8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. - 'buildtools_revision': '5378d73123b64907773cc5c1bb027b2f765ff00a', + 'buildtools_revision': 'e84114dbe2b65428951c876349b6a3ff1afbfccd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -192,7 +192,7 @@ Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'beef68513861e11156899b1f763097c31808c418', 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'b6635d741fcb7030b62874f9bc8ae39628e127cc', # commit position 12291 + Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '6a9674787c1dac66a0f40df132da9028e3dfb886', # commit position 12410 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98', @@ -216,7 +216,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'cc6714b1ec7b4f6c7f0c37338aaca193b503c9cb', # commit position 12409 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'fcc3833d12a7f24dbe71f21791016ff4f10e04f8', # commit position 12447 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java b/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java index e43b840..be319dd 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java +++ b/android_webview/java/src/org/chromium/android_webview/AwGLFunctor.java
@@ -33,7 +33,8 @@ } private final long mNativeAwGLFunctor; - private final DestroyRunnable mDestroyRunnable; + // Same gc-life time as this, but does not reference any members like |mContainerView|. + private final Object mLifetimeObject; private final CleanupReference mCleanupReference; private final AwContents.NativeGLDelegate mNativeGLDelegate; private final ViewGroup mContainerView; @@ -41,8 +42,9 @@ public AwGLFunctor(AwContents.NativeGLDelegate nativeGLDelegate, ViewGroup containerView) { mNativeAwGLFunctor = nativeCreate(this); - mDestroyRunnable = new DestroyRunnable(mNativeAwGLFunctor); - mCleanupReference = new CleanupReference(mDestroyRunnable, mDestroyRunnable); + mLifetimeObject = new Object(); + mCleanupReference = + new CleanupReference(mLifetimeObject, new DestroyRunnable(mNativeAwGLFunctor)); mNativeGLDelegate = nativeGLDelegate; mContainerView = containerView; if (mNativeGLDelegate.supportsDrawGLFunctorReleasedCallback()) { @@ -67,7 +69,7 @@ } public Object getNativeLifetimeObject() { - return mDestroyRunnable; + return mLifetimeObject; } public boolean requestDrawGLForCanvas(Canvas canvas) {
diff --git a/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml b/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml index 2224f83..70c6c379 100644 --- a/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml +++ b/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
@@ -61,7 +61,8 @@ android:name="org.chromium.webview_shell.WebViewBrowserActivity" android:label="@string/title_activity_browser" android:exported="true" - android:windowSoftInputMode="adjustResize"> + android:windowSoftInputMode="adjustResize" + android:configChanges="orientation|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index f37c43c..dd6f76eb 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -81,6 +81,7 @@ "//build/config/linux:xfixes", ] deps += [ + "//ui/events/devices/x11", "//ui/events/platform", "//ui/gfx/x", ]
diff --git a/ash/ash.gyp b/ash/ash.gyp index 5ff00c3..68af976b 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp
@@ -1041,6 +1041,7 @@ 'dependencies': [ '../build/linux/system.gyp:x11', '../build/linux/system.gyp:xfixes', + '../ui/events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../ui/gfx/x/gfx_x11.gyp:gfx_x11', ], }],
diff --git a/ash/display/display_color_manager_chromeos_unittest.cc b/ash/display/display_color_manager_chromeos_unittest.cc index e710c876..9766c10 100644 --- a/ash/display/display_color_manager_chromeos_unittest.cc +++ b/ash/display/display_color_manager_chromeos_unittest.cc
@@ -4,6 +4,7 @@ #include "ash/display/display_color_manager_chromeos.h" +#include "base/command_line.h" #include "base/files/file_util.h" #include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" @@ -14,6 +15,7 @@ #include "base/test/sequenced_worker_pool_owner.h" #include "chromeos/chromeos_paths.h" #include "components/quirks/quirks_manager.h" +#include "components/quirks/switches.h" #include "net/url_request/url_request_context_getter.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/display/chromeos/test/action_logger_util.h" @@ -111,6 +113,9 @@ class DisplayColorManagerTest : public testing::Test { public: void SetUp() override { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + quirks::switches::kDisableQuirksClient); + pool_owner_.reset( new base::SequencedWorkerPoolOwner(3, "DisplayColorManagerTest")); log_.reset(new ui::test::ActionLogger());
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc index 09fa992..e0171545 100644 --- a/ash/shell/content/client/shell_browser_main_parts.cc +++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -37,7 +37,7 @@ #include "ui/wm/core/wm_state.h" #if defined(USE_X11) -#include "ui/events/devices/x11/touch_factory_x11.h" +#include "ui/events/devices/x11/touch_factory_x11.h" // nogncheck #endif #if defined(OS_CHROMEOS)
diff --git a/ash/touch/touch_hud_debug.cc b/ash/touch/touch_hud_debug.cc index e690735ca..fcbc426 100644 --- a/ash/touch/touch_hud_debug.cc +++ b/ash/touch/touch_hud_debug.cc
@@ -4,6 +4,10 @@ #include "ash/touch/touch_hud_debug.h" +#include <algorithm> +#include <string> +#include <vector> + #include "ash/display/display_manager.h" #include "ash/root_window_controller.h" #include "ash/shell.h" @@ -28,7 +32,7 @@ #include <X11/extensions/XInput2.h> #include <X11/Xlib.h> -#include "ui/events/devices/x11/device_data_manager_x11.h" +#include "ui/events/devices/x11/device_data_manager_x11.h" // nogncheck #endif namespace ash {
diff --git a/build/all.gyp b/build/all.gyp index b51b9d9b..71ed6be 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -30,6 +30,7 @@ '../sql/sql.gyp:*', '../testing/gmock.gyp:*', '../testing/gtest.gyp:*', + '../third_party/boringssl/boringssl.gyp:*', '../third_party/icu/icu.gyp:*', '../third_party/libxml/libxml.gyp:*', '../third_party/sqlite/sqlite.gyp:*', @@ -167,11 +168,6 @@ '<(libjpeg_gyp_path):*', ], }], - ['use_openssl==0 and OS=="ios"', { - 'dependencies': [ - '../third_party/nss/nss.gyp:*', - ], - }], ['OS=="win" or OS=="ios" or OS=="linux"', { 'dependencies': [ '../breakpad/breakpad.gyp:*', @@ -254,17 +250,7 @@ '../remoting/remoting_all.gyp:remoting_all', ], }], - ['use_openssl==0', { - 'dependencies': [ - '../net/third_party/nss/ssl.gyp:*', - ], - }], - ['use_openssl==1', { - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:*', - ], - }], - ['use_openssl==1 and OS!="ios"', { + ['OS!="ios"', { 'dependencies': [ '../third_party/boringssl/boringssl_tests.gyp:*', ],
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py index 5d8731f..2e18e8d5 100755 --- a/build/android/buildbot/bb_device_steps.py +++ b/build/android/buildbot/bb_device_steps.py
@@ -498,51 +498,54 @@ def RunGPUTests(options): + exit_code = 0 revision = _GetRevision(options) builder_name = options.build_properties.get('buildername', 'noname') bb_annotations.PrintNamedStep('pixel_tests') - RunCmd(['content/test/gpu/run_gpu_test.py', - 'pixel', '-v', - '--browser', - 'android-content-shell', - '--build-revision', - str(revision), - '--upload-refimg-to-cloud-storage', - '--refimg-cloud-storage-bucket', - 'chromium-gpu-archive/reference-images', - '--os-type', - 'android', - '--test-machine-name', - EscapeBuilderName(builder_name), - '--android-blacklist-file', - 'out/bad_devices.json']) + exit_code = RunCmd(['content/test/gpu/run_gpu_test.py', + 'pixel', '-v', + '--browser', + 'android-content-shell', + '--build-revision', + str(revision), + '--upload-refimg-to-cloud-storage', + '--refimg-cloud-storage-bucket', + 'chromium-gpu-archive/reference-images', + '--os-type', + 'android', + '--test-machine-name', + EscapeBuilderName(builder_name), + '--android-blacklist-file', + 'out/bad_devices.json']) or exit_code bb_annotations.PrintNamedStep('webgl_conformance_tests') - RunCmd(['content/test/gpu/run_gpu_test.py', '-v', - '--browser=android-content-shell', 'webgl_conformance', - '--webgl-conformance-version=1.0.1', - '--android-blacklist-file', - 'out/bad_devices.json']) + exit_code = RunCmd(['content/test/gpu/run_gpu_test.py', '-v', + '--browser=android-content-shell', 'webgl_conformance', + '--webgl-conformance-version=1.0.1', + '--android-blacklist-file', + 'out/bad_devices.json']) or exit_code bb_annotations.PrintNamedStep('android_webview_webgl_conformance_tests') - RunCmd(['content/test/gpu/run_gpu_test.py', '-v', - '--browser=android-webview-shell', 'webgl_conformance', - '--webgl-conformance-version=1.0.1', - '--android-blacklist-file', - 'out/bad_devices.json']) + exit_code = RunCmd(['content/test/gpu/run_gpu_test.py', '-v', + '--browser=android-webview-shell', 'webgl_conformance', + '--webgl-conformance-version=1.0.1', + '--android-blacklist-file', + 'out/bad_devices.json']) or exit_code bb_annotations.PrintNamedStep('gpu_rasterization_tests') - RunCmd(['content/test/gpu/run_gpu_test.py', - 'gpu_rasterization', '-v', - '--browser', - 'android-content-shell', - '--build-revision', - str(revision), - '--test-machine-name', - EscapeBuilderName(builder_name), - '--android-blacklist-file', - 'out/bad_devices.json']) + exit_code = RunCmd(['content/test/gpu/run_gpu_test.py', + 'gpu_rasterization', '-v', + '--browser', + 'android-content-shell', + '--build-revision', + str(revision), + '--test-machine-name', + EscapeBuilderName(builder_name), + '--android-blacklist-file', + 'out/bad_devices.json']) or exit_code + + return exit_code def RunPythonUnitTests(_options): @@ -653,6 +656,7 @@ def MainTestWrapper(options): + exit_code = 0 try: # Spawn logcat monitor SpawnLogcatMonitor() @@ -667,7 +671,8 @@ InstallApk(options, install_obj, print_step=True) if options.test_filter: - bb_utils.RunSteps(options.test_filter, GetTestStepCmds(), options) + exit_code = bb_utils.RunSteps( + options.test_filter, GetTestStepCmds(), options) or exit_code if options.coverage_bucket: coverage_html = GenerateJavaCoverageReport(options) @@ -676,7 +681,10 @@ shutil.rmtree(coverage_html, ignore_errors=True) if options.experimental: - RunTestSuites(options, gtest_config.EXPERIMENTAL_TEST_SUITES) + exit_code = RunTestSuites( + options, gtest_config.EXPERIMENTAL_TEST_SUITES) or exit_code + + return exit_code finally: # Run all post test steps @@ -768,7 +776,7 @@ setattr(options, 'coverage_dir', os.path.join(CHROME_OUT_DIR, options.target, 'coverage')) - MainTestWrapper(options) + return MainTestWrapper(options) if __name__ == '__main__':
diff --git a/build/android/buildbot/bb_utils.py b/build/android/buildbot/bb_utils.py index 223f4ae..71ac7b2 100644 --- a/build/android/buildbot/bb_utils.py +++ b/build/android/buildbot/bb_utils.py
@@ -96,6 +96,9 @@ print >> sys.stderr, 'FATAL: Unknown steps %s' % list(unknown_steps) sys.exit(1) + exit_code = 0 for step, cmd in step_cmds: if step in steps: - cmd(options) + exit_code = cmd(options) or exit_code + + return exit_code
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py index 832b4ad..c1281ff 100644 --- a/build/android/pylib/utils/isolator.py +++ b/build/android/pylib/utils/isolator.py
@@ -47,7 +47,6 @@ 'use_custom_libcxx': '0', 'use_instrumented_libraries': '0', 'use_prebuilt_instrumented_libraries': '0', - 'use_openssl': '0', 'use_ozone': '0', 'use_x11': '0', 'v8_use_external_startup_data': '1', @@ -174,4 +173,3 @@ shutil.move(os.path.join(deps_product_dir, p), self._isolate_deps_dir) os.rmdir(deps_product_dir) os.rmdir(deps_out_dir) -
diff --git a/build/common.gypi b/build/common.gypi index bf6732a8..2fec6dd 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -744,15 +744,6 @@ 'use_nss_certs%': 0, }], - # NSS verifier usage. - # On non-OpenSSL iOS configurations, certificates use the operating - # system library, but the verifier uses the bundled copy of NSS. - ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris") or (OS=="ios" and use_openssl==0)', { - 'use_nss_verifier%': 1, - }, { - 'use_nss_verifier%': 0, - }], - # libudev usage. This currently only affects the content layer. ['OS=="linux" and embedded==0', { 'use_udev%': 1, @@ -1170,7 +1161,6 @@ 'use_openssl%': '<(use_openssl)', 'use_openssl_certs%': '<(use_openssl_certs)', 'use_nss_certs%': '<(use_nss_certs)', - 'use_nss_verifier%': '<(use_nss_verifier)', 'use_udev%': '<(use_udev)', 'os_bsd%': '<(os_bsd)', 'os_posix%': '<(os_posix)', @@ -2139,9 +2129,6 @@ ['use_nss_certs==1', { 'grit_defines': ['-D', 'use_nss_certs'], }], - ['use_nss_verifier==1', { - 'grit_defines': ['-D', 'use_nss_verifier'], - }], ['use_ozone==1', { 'grit_defines': ['-D', 'use_ozone'], }], @@ -3075,15 +3062,11 @@ ['<(use_libpci)==1', { 'defines': ['USE_LIBPCI=1'], }], - ['<(use_openssl)==1', { - 'defines': ['USE_OPENSSL=1'], - }], ['<(use_openssl_certs)==1', { 'defines': ['USE_OPENSSL_CERTS=1'], }], ['>(nacl_untrusted_build)==1', { 'defines': [ - 'USE_OPENSSL=1', 'USE_OPENSSL_CERTS=1', ], }], @@ -3093,9 +3076,6 @@ ['<(use_nss_certs)==1 and >(nacl_untrusted_build)==0', { 'defines': ['USE_NSS_CERTS=1'], }], - ['<(use_nss_verifier)==1 and >(nacl_untrusted_build)==0', { - 'defines': ['USE_NSS_VERIFIER=1'], - }], ['<(chromeos)==1 and >(nacl_untrusted_build)==0', { 'defines': ['OS_CHROMEOS=1'], }],
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index b6d0b71f..d4caba48 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -124,18 +124,12 @@ if (use_glib) { defines += [ "USE_GLIB=1" ] } - if (use_openssl) { - defines += [ "USE_OPENSSL=1" ] - } if (use_openssl_certs) { defines += [ "USE_OPENSSL_CERTS=1" ] } if (use_nss_certs) { defines += [ "USE_NSS_CERTS=1" ] } - if (use_nss_verifier) { - defines += [ "USE_NSS_VERIFIER=1" ] - } if (use_ozone) { defines += [ "USE_OZONE=1" ] }
diff --git a/build/config/crypto.gni b/build/config/crypto.gni index 2b15b1c..5c940f2 100644 --- a/build/config/crypto.gni +++ b/build/config/crypto.gni
@@ -22,12 +22,6 @@ # is unsupported. use_openssl_certs = is_android || is_nacl -# True if NSS is used for certificate handling. 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. +# True if NSS is used for certificate handling. It is possible to use OpenSSL +# for the crypto library, but NSS for the platform certificate library. use_nss_certs = is_linux - -# True if NSS is used for certificate verification. On non-OpenSSL iOS -# configurations, certificates use the operating system library, but the -# verifier uses the bundled copy of NSS. -use_nss_verifier = use_nss_certs || (is_ios && !use_openssl)
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi index 83cf2de..f413afb 100644 --- a/build/gn_migration.gypi +++ b/build/gn_migration.gypi
@@ -83,6 +83,33 @@ '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests', '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests', '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_ecdsa_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_bn_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_pqueue_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_digest_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_cipher_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_hkdf_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_constant_time_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_thread_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_base64_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_gcm_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_bytestring_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_evp_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_dsa_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_rsa_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_hmac_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_aead_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_ssl_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_err_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_lhash_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_pbkdf_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_dh_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs12_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_example_mul', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_ec_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_bio_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs7_test', + '../third_party/boringssl/boringssl_tests.gyp:boringssl_unittests', '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests', '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests', '../third_party/smhasher/smhasher.gyp:pmurhash', @@ -641,38 +668,6 @@ }], ], }], - ['use_openssl==1', { - 'dependencies': [ - # TODO(GYP): All of these targets still need to be converted. - '../third_party/boringssl/boringssl_tests.gyp:boringssl_ecdsa_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_bn_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_pqueue_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_digest_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_cipher_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_hkdf_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_constant_time_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_thread_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_base64_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_gcm_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_bytestring_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_evp_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_dsa_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_rsa_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_hmac_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_aead_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_ssl_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_err_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_lhash_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_pbkdf_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_dh_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs12_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_example_mul', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_ec_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_bio_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs7_test', - '../third_party/boringssl/boringssl_tests.gyp:boringssl_unittests', - ], - }], ['chromeos==1', { 'dependencies': [ '../content/content_shell_and_tests.gyp:jpeg_decode_accelerator_unittest',
diff --git a/build/isolate.gypi b/build/isolate.gypi index ea3a91b..197e455 100644 --- a/build/isolate.gypi +++ b/build/isolate.gypi
@@ -90,7 +90,6 @@ '--config-variable', 'use_instrumented_libraries=<(use_instrumented_libraries)', '--config-variable', 'use_prebuilt_instrumented_libraries=<(use_prebuilt_instrumented_libraries)', - '--config-variable', 'use_openssl=<(use_openssl)', '--config-variable', 'use_ozone=<(use_ozone)', '--config-variable', 'use_x11=<(use_x11)', '--config-variable', 'v8_use_external_startup_data=<(v8_use_external_startup_data)',
diff --git a/build/linux/system.gyp b/build/linux/system.gyp index c4a3691..553a5a7 100644 --- a/build/linux/system.gyp +++ b/build/linux/system.gyp
@@ -1246,27 +1246,13 @@ 'type': 'none', 'conditions': [ ['_toolset=="target"', { + 'dependencies': [ + '../../third_party/boringssl/boringssl.gyp:boringssl', + ], 'conditions': [ - ['use_openssl==1', { - 'dependencies': [ - '../../third_party/boringssl/boringssl.gyp:boringssl', - ], - }, { - 'dependencies': [ - '../../net/third_party/nss/ssl.gyp:libssl', - ], - 'direct_dependent_settings': { - 'include_dirs+': [ - # We need for our local copies of the libssl3 headers to come - # 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 + # Link in the system NSS if it is used for the platform certificate # library (use_nss_certs==1). - ['use_openssl==0 or use_nss_certs==1', { + ['use_nss_certs==1', { 'direct_dependent_settings': { 'cflags': [ '<!@(<(pkg-config) --cflags nss)',
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index 5ba1aad..bac8f243 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -150,6 +150,79 @@ draw_properties_.content_rect = content_rect; } +void RenderSurfaceImpl::SetContentRectForTesting(const gfx::Rect& rect) { + SetContentRect(rect); +} + +gfx::Rect RenderSurfaceImpl::CalculateClippedAccumulatedContentRect() { + if (owning_layer_->replica_layer() || owning_layer_->HasCopyRequest() || + !is_clipped()) + return accumulated_content_rect(); + + if (accumulated_content_rect().IsEmpty()) + return gfx::Rect(); + + // Calculate projection from the target surface rect to local + // space. Non-invertible draw transforms means no able to bring clipped rect + // in target space back to local space, early out without clip. + gfx::Transform target_to_surface(gfx::Transform::kSkipInitialization); + if (!draw_transform().GetInverse(&target_to_surface)) + return accumulated_content_rect(); + + // Clip rect is in target space. Bring accumulated content rect to + // target space in preparation for clipping. + gfx::Rect accumulated_rect_in_target_space = + MathUtil::MapEnclosingClippedRect(draw_transform(), + accumulated_content_rect()); + // If accumulated content rect is contained within clip rect, early out + // without clipping. + if (clip_rect().Contains(accumulated_rect_in_target_space)) + return accumulated_content_rect(); + + gfx::Rect clipped_accumulated_rect_in_target_space = clip_rect(); + clipped_accumulated_rect_in_target_space.Intersect( + accumulated_rect_in_target_space); + + if (clipped_accumulated_rect_in_target_space.IsEmpty()) + return gfx::Rect(); + + gfx::Rect clipped_accumulated_rect_in_local_space = + MathUtil::ProjectEnclosingClippedRect( + target_to_surface, clipped_accumulated_rect_in_target_space); + // Bringing clipped accumulated rect back to local space may result + // in inflation due to axis-alignment. + clipped_accumulated_rect_in_local_space.Intersect(accumulated_content_rect()); + return clipped_accumulated_rect_in_local_space; +} + +void RenderSurfaceImpl::CalculateContentRectFromAccumulatedContentRect( + int max_texture_size) { + // Root render surface use viewport, and does not calculate content rect. + DCHECK_NE(render_target(), this); + + // Surface's content rect is the clipped accumulated content rect. By default + // use accumulated content rect, and then try to clip it. + gfx::Rect surface_content_rect = CalculateClippedAccumulatedContentRect(); + + // The RenderSurfaceImpl backing texture cannot exceed the maximum + // supported texture size. + surface_content_rect.set_width( + std::min(surface_content_rect.width(), max_texture_size)); + surface_content_rect.set_height( + std::min(surface_content_rect.height(), max_texture_size)); + + SetContentRect(surface_content_rect); +} + +void RenderSurfaceImpl::SetContentRectToViewport() { + // Only root render surface use viewport as content rect. + DCHECK_EQ(render_target(), this); + gfx::Rect viewport = gfx::ToEnclosingRect(owning_layer_->layer_tree_impl() + ->property_trees() + ->clip_tree.ViewportClip()); + SetContentRect(viewport); +} + void RenderSurfaceImpl::ClearAccumulatedContentRect() { accumulated_content_rect_ = gfx::Rect(); }
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h index d738646..488cd5f 100644 --- a/cc/layers/render_surface_impl.h +++ b/cc/layers/render_surface_impl.h
@@ -117,7 +117,9 @@ contributes_to_drawn_surface_ = contributes_to_drawn_surface; } - void SetContentRect(const gfx::Rect& content_rect); + void CalculateContentRectFromAccumulatedContentRect(int max_texture_size); + void SetContentRectToViewport(); + void SetContentRectForTesting(const gfx::Rect& rect); gfx::Rect content_rect() const { return draw_properties_.content_rect; } void ClearAccumulatedContentRect(); @@ -167,6 +169,9 @@ int EffectTreeIndex() const; private: + void SetContentRect(const gfx::Rect& content_rect); + gfx::Rect CalculateClippedAccumulatedContentRect(); + LayerImpl* owning_layer_; // Container for properties that render surfaces need to compute before they
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc index df85cb0..2c211779 100644 --- a/cc/layers/render_surface_unittest.cc +++ b/cc/layers/render_surface_unittest.cc
@@ -54,7 +54,8 @@ // Currently, the content_rect, clip_rect, and // owning_layer->layerPropertyChanged() are the only sources of change. EXECUTE_AND_VERIFY_SURFACE_CHANGED(render_surface->SetClipRect(test_rect)); - EXECUTE_AND_VERIFY_SURFACE_CHANGED(render_surface->SetContentRect(test_rect)); + EXECUTE_AND_VERIFY_SURFACE_CHANGED( + render_surface->SetContentRectForTesting(test_rect)); owning_layer->SetOpacity(0.5f); EXPECT_TRUE(render_surface->SurfacePropertyChanged()); @@ -66,7 +67,7 @@ EXECUTE_AND_VERIFY_SURFACE_DID_NOT_CHANGE( render_surface->SetClipRect(test_rect)); EXECUTE_AND_VERIFY_SURFACE_DID_NOT_CHANGE( - render_surface->SetContentRect(test_rect)); + render_surface->SetContentRectForTesting(test_rect)); std::unique_ptr<LayerImpl> dummy_mask = LayerImpl::Create(host_impl.active_tree(), 2); @@ -110,7 +111,7 @@ gfx::Transform origin; origin.Translate(30, 40); - render_surface->SetContentRect(content_rect); + render_surface->SetContentRectForTesting(content_rect); render_surface->SetClipRect(clip_rect); render_surface->SetDrawOpacity(1.f); @@ -173,7 +174,7 @@ origin.Translate(30.0, 40.0); render_surface->SetScreenSpaceTransform(origin); - render_surface->SetContentRect(content_rect); + render_surface->SetContentRectForTesting(content_rect); TestRenderPassSink pass_sink;
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index f86b301..8982605 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -473,8 +473,8 @@ ClipNode* parent_clip_node = clip_tree->parent(clip_node); gfx::Transform parent_to_current; - const TransformNode* parent_transform_node = - transform_tree.Node(parent_clip_node->data.transform_id); + const TransformNode* parent_target_transform_node = + transform_tree.Node(parent_clip_node->data.target_id); bool success = true; // Clips must be combined in target space. We cannot, for example, combine @@ -491,16 +491,17 @@ parent_clip_node->data.combined_clip_in_target_space; gfx::RectF parent_clip_in_target_space = parent_clip_node->data.clip_in_target_space; - if (parent_clip_node->data.target_id != clip_node->data.target_id && + if (parent_target_transform_node && + parent_target_transform_node->id != clip_node->data.target_id && non_root_surfaces_enabled) { success &= transform_tree.ComputeTransformWithDestinationSublayerScale( - parent_clip_node->data.target_id, clip_node->data.target_id, + parent_target_transform_node->id, clip_node->data.target_id, &parent_to_current); - if (parent_transform_node->data.sublayer_scale.x() > 0 && - parent_transform_node->data.sublayer_scale.y() > 0) + if (parent_target_transform_node->data.sublayer_scale.x() > 0 && + parent_target_transform_node->data.sublayer_scale.y() > 0) parent_to_current.Scale( - 1.f / parent_transform_node->data.sublayer_scale.x(), - 1.f / parent_transform_node->data.sublayer_scale.y()); + 1.f / parent_target_transform_node->data.sublayer_scale.x(), + 1.f / parent_target_transform_node->data.sublayer_scale.y()); // If we can't compute a transform, it's because we had to use the inverse // of a singular transform. We won't draw in this case, so there's no need // to compute clips.
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index b94c34a..5c3ef1d1 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -195,56 +195,6 @@ top_controls_delta = proto.top_controls_delta(); } -inline gfx::Rect CalculateVisibleRectWithCachedLayerRect( - const gfx::Rect& target_surface_rect, - const gfx::Rect& layer_bound_rect, - const gfx::Rect& layer_rect_in_target_space, - const gfx::Transform& transform) { - if (layer_rect_in_target_space.IsEmpty()) - return gfx::Rect(); - - // Is this layer fully contained within the target surface? - if (target_surface_rect.Contains(layer_rect_in_target_space)) - return layer_bound_rect; - - // If the layer doesn't fill up the entire surface, then find the part of - // the surface rect where the layer could be visible. This avoids trying to - // project surface rect points that are behind the projection point. - gfx::Rect minimal_surface_rect = target_surface_rect; - minimal_surface_rect.Intersect(layer_rect_in_target_space); - - if (minimal_surface_rect.IsEmpty()) - return gfx::Rect(); - - // Project the corners of the target surface rect into the layer space. - // This bounding rectangle may be larger than it needs to be (being - // axis-aligned), but is a reasonable filter on the space to consider. - // Non-invertible transforms will create an empty rect here. - - gfx::Transform surface_to_layer(gfx::Transform::kSkipInitialization); - if (!transform.GetInverse(&surface_to_layer)) { - // Because we cannot use the surface bounds to determine what portion of - // the layer is visible, we must conservatively assume the full layer is - // visible. - return layer_bound_rect; - } - - gfx::Rect layer_rect = MathUtil::ProjectEnclosingClippedRect( - surface_to_layer, minimal_surface_rect); - layer_rect.Intersect(layer_bound_rect); - return layer_rect; -} - -gfx::Rect LayerTreeHostCommon::CalculateVisibleRect( - const gfx::Rect& target_surface_rect, - const gfx::Rect& layer_bound_rect, - const gfx::Transform& transform) { - gfx::Rect layer_in_surface_space = - MathUtil::MapEnclosingClippedRect(transform, layer_bound_rect); - return CalculateVisibleRectWithCachedLayerRect( - target_surface_rect, layer_bound_rect, layer_in_surface_space, transform); -} - static inline bool IsRootLayer(const Layer* layer) { return !layer->parent(); } @@ -617,36 +567,13 @@ for (LayerImpl* layer : base::Reversed(*render_surface_layer_list)) { if (layer_tree_impl->IsRootLayer(layer)) { // The root layer's surface content rect is always the entire viewport. - gfx::Rect viewport = - gfx::ToEnclosingRect(property_trees->clip_tree.ViewportClip()); - layer->render_surface()->SetContentRect(viewport); + layer->render_surface()->SetContentRectToViewport(); continue; } - RenderSurfaceImpl* surface = layer->render_surface(); - gfx::Rect surface_content_rect = surface->accumulated_content_rect(); - - if (!layer->replica_layer() && !layer->HasCopyRequest() && - surface->is_clipped()) { - // Here, we clip the render surface's content rect with its clip rect. - // As the clip rect of render surface is in the surface's target - // space, we first map the content rect into the target space, - // intersect it with clip rect and project back the result to the - // surface space. - if (!surface_content_rect.IsEmpty()) { - gfx::Rect surface_clip_rect = LayerTreeHostCommon::CalculateVisibleRect( - surface->clip_rect(), surface_content_rect, - surface->draw_transform()); - surface_content_rect.Intersect(surface_clip_rect); - } - } - // The RenderSurfaceImpl backing texture cannot exceed the maximum - // supported texture size. - surface_content_rect.set_width( - std::min(surface_content_rect.width(), max_texture_size)); - surface_content_rect.set_height( - std::min(surface_content_rect.height(), max_texture_size)); - surface->SetContentRect(surface_content_rect); + // Now all contributing drawable content rect has been accumulated to this + // render surface, calculate the content rect. + surface->CalculateContentRectFromAccumulatedContentRect(max_texture_size); // Now the render surface's content rect is calculated correctly, it could // contribute to its render target.
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h index c136f96..8d1b5e7 100644 --- a/cc/trees/layer_tree_host_common.h +++ b/cc/trees/layer_tree_host_common.h
@@ -45,10 +45,6 @@ class CC_EXPORT LayerTreeHostCommon { public: - static gfx::Rect CalculateVisibleRect(const gfx::Rect& target_surface_rect, - const gfx::Rect& layer_bound_rect, - const gfx::Transform& transform); - struct CC_EXPORT CalcDrawPropsMainInputsForTesting { public: CalcDrawPropsMainInputsForTesting(Layer* root_layer,
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index bb3b18d..ce72cad 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -104,6 +104,41 @@ : LayerTreeHostCommonTest(LayerTreeSettingsScaleContent()) {} }; +class LayerTreeHostCommonDrawRectsTest : public LayerTreeHostCommonTest { + public: + LayerTreeHostCommonDrawRectsTest() : LayerTreeHostCommonTest() {} + + LayerImpl* TestVisibleRectAndDrawableContentRect( + const gfx::Rect& target_rect, + const gfx::Transform& layer_transform, + const gfx::Rect& layer_rect) { + LayerImpl* root = root_layer(); + LayerImpl* target = AddChild<LayerImpl>(root); + LayerImpl* drawing_layer = AddChild<LayerImpl>(target); + + root->SetDrawsContent(true); + target->SetDrawsContent(true); + target->SetMasksToBounds(true); + drawing_layer->SetDrawsContent(true); + + gfx::Transform identity; + + SetLayerPropertiesForTesting(root, identity, gfx::Point3F(), gfx::PointF(), + gfx::Size(500, 500), true, false, true); + SetLayerPropertiesForTesting(target, identity, gfx::Point3F(), + gfx::PointF(target_rect.origin()), + target_rect.size(), true, false, true); + SetLayerPropertiesForTesting(drawing_layer, layer_transform, gfx::Point3F(), + gfx::PointF(layer_rect.origin()), + layer_rect.size(), true, false, false); + + host_impl()->active_tree()->property_trees()->needs_rebuild = true; + ExecuteCalculateDrawProperties(root); + + return drawing_layer; + } +}; + TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) { // Sanity check: For layers positioned at zero, with zero size, // and with identity transforms, then the draw transform, @@ -2696,70 +2731,47 @@ EXPECT_TRUE(great_grand_child->screen_space_transform_is_animating()); } -TEST_F(LayerTreeHostCommonTest, VisibleRectForIdentityTransform) { - // Test the calculateVisibleRect() function works correctly for identity - // transforms. +TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsForIdentityTransform) { + // Test visible layer rect and drawable content rect are calculated correctly + // correctly for identity transforms. gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); gfx::Transform layer_to_surface_transform; // Case 1: Layer is contained within the surface. gfx::Rect layer_content_rect = gfx::Rect(10, 10, 30, 30); - gfx::Rect expected = gfx::Rect(10, 10, 30, 30); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + gfx::Rect expected_visible_layer_rect = gfx::Rect(30, 30); + gfx::Rect expected_drawable_content_rect = gfx::Rect(10, 10, 30, 30); + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 2: Layer is outside the surface rect. layer_content_rect = gfx::Rect(120, 120, 30, 30); - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_TRUE(actual.IsEmpty()); + expected_visible_layer_rect = gfx::Rect(); + expected_drawable_content_rect = gfx::Rect(); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 3: Layer is partially overlapping the surface rect. layer_content_rect = gfx::Rect(80, 80, 30, 30); - expected = gfx::Rect(80, 80, 20, 20); - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + expected_visible_layer_rect = gfx::Rect(20, 20); + expected_drawable_content_rect = gfx::Rect(80, 80, 20, 20); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) { - // Test the calculateVisibleRect() function works correctly for scaling - // transforms. - - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(0, 0, 30, 30); - gfx::Transform layer_to_surface_transform; - - // Case 1: Layer is contained within the surface. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(10.0, 10.0); - gfx::Rect expected = gfx::Rect(0, 0, 30, 30); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); - - // Case 2: Layer is outside the surface rect. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(120.0, 120.0); - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_TRUE(actual.IsEmpty()); - - // Case 3: Layer is partially overlapping the surface rect. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(80.0, 80.0); - expected = gfx::Rect(0, 0, 20, 20); - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); -} - -TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) { - // Test the calculateVisibleRect() function works correctly for rotations - // about z-axis (i.e. 2D rotations). Remember that calculateVisibleRect() - // should return the g in the layer's space. +TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsFor2DRotations) { + // Test visible layer rect and drawable content rect are calculated correctly + // for rotations about z-axis (i.e. 2D rotations). gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); gfx::Rect layer_content_rect = gfx::Rect(0, 0, 30, 30); @@ -2769,18 +2781,25 @@ layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.Translate(50.0, 50.0); layer_to_surface_transform.Rotate(45.0); - gfx::Rect expected = gfx::Rect(0, 0, 30, 30); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + gfx::Rect expected_visible_layer_rect = gfx::Rect(30, 30); + gfx::Rect expected_drawable_content_rect = gfx::Rect(28, 50, 44, 43); + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 2: Layer is outside the surface rect. layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.Translate(-50.0, 0.0); layer_to_surface_transform.Rotate(45.0); - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_TRUE(actual.IsEmpty()); + expected_visible_layer_rect = gfx::Rect(); + expected_drawable_content_rect = gfx::Rect(); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 3: The layer is rotated about its top-left corner. In surface space, // the layer is oriented diagonally, with the left half outside of the render @@ -2789,10 +2808,13 @@ // and bottom-right corners of the layer are still visible. layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.Rotate(45.0); - expected = gfx::Rect(0, 0, 30, 30); - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + expected_visible_layer_rect = gfx::Rect(30, 30); + expected_drawable_content_rect = gfx::Rect(22, 43); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 4: The layer is rotated about its top-left corner, and translated // upwards. In surface space, the layer is oriented diagonally, with only the @@ -2802,15 +2824,19 @@ layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.Translate(0.0, -sqrt(2.0) * 15.0); layer_to_surface_transform.Rotate(45.0); - expected = gfx::Rect(15, 0, 15, 30); // Right half of layer bounds. - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + // Right half of layer bounds. + expected_visible_layer_rect = gfx::Rect(15, 0, 15, 30); + expected_drawable_content_rect = gfx::Rect(22, 22); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) { - // Test that the calculateVisibleRect() function works correctly for 3d - // transforms. +TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsFor3dOrthographicTransform) { + // Test visible layer rect and drawable content rect are calculated correctly + // for 3d transforms. gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); gfx::Rect layer_content_rect = gfx::Rect(0, 0, 100, 100); @@ -2818,32 +2844,40 @@ // Case 1: Orthographic projection of a layer rotated about y-axis by 45 // degrees, should be fully contained in the render surface. + // 100 is the un-rotated layer width; divided by sqrt(2) is the rotated width. layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.RotateAboutYAxis(45.0); - gfx::Rect expected = gfx::Rect(0, 0, 100, 100); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + gfx::Rect expected_visible_layer_rect = gfx::Rect(100, 100); + gfx::Rect expected_drawable_content_rect = gfx::Rect(71, 100); + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 2: Orthographic projection of a layer rotated about y-axis by 45 // degrees, but shifted to the side so only the right-half the layer would be // visible on the surface. - // 100 is the un-rotated layer width; divided by sqrt(2) is the rotated width. + // 50 is the un-rotated layer width; divided by sqrt(2) is the rotated width. SkMScalar half_width_of_rotated_layer = SkDoubleToMScalar((100.0 / sqrt(2.0)) * 0.5); layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.Translate(-half_width_of_rotated_layer, 0.0); layer_to_surface_transform.RotateAboutYAxis(45.0); // Rotates about the left // edge of the layer. - expected = gfx::Rect(50, 0, 50, 100); // Tight half of the layer. - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + // Tight half of the layer. + expected_visible_layer_rect = gfx::Rect(50, 0, 50, 100); + expected_drawable_content_rect = gfx::Rect(36, 100); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) { - // Test the calculateVisibleRect() function works correctly when the layer has - // a perspective projection onto the target surface. +TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsFor3dPerspectiveTransform) { + // Test visible layer rect and drawable content rect are calculated correctly + // when the layer has a perspective projection onto the target surface. gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); gfx::Rect layer_content_rect = gfx::Rect(-50, -50, 200, 200); @@ -2863,10 +2897,15 @@ // This translate places the layer in front of the surface's projection plane. layer_to_surface_transform.Translate3d(0.0, 0.0, -27.0); - gfx::Rect expected = gfx::Rect(-50, -50, 200, 200); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + // Layer position is (-50, -50), visible rect in layer space is layer bounds + // offset by layer position. + gfx::Rect expected_visible_layer_rect = gfx::Rect(50, 50, 150, 150); + gfx::Rect expected_drawable_content_rect = gfx::Rect(38, 38); + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); // Case 2: same projection as before, except that the layer is also translated // to the side, so that only the right half of the layer should be visible. @@ -2874,20 +2913,23 @@ // Explanation of expected result: The perspective ratio is (z distance // between layer and camera origin) / (z distance between projection plane and // camera origin) == ((-27 - 9) / 9) Then, by similar triangles, if we want to - // move a layer by translating -50 units in projected surface units (so that + // move a layer by translating -25 units in projected surface units (so that // only half of it is visible), then we would need to translate by (-36 / 9) * - // -50 == -200 in the layer's units. - layer_to_surface_transform.Translate3d(-200.0, 0.0, 0.0); - expected = gfx::Rect(gfx::Point(50, -50), - gfx::Size(100, 200)); // The right half of the layer's - // bounding rect. - actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + // -25 == -100 in the layer's units. + layer_to_surface_transform.Translate3d(-100.0, 0.0, 0.0); + // Visible layer rect is moved by 100, and drawable content rect is in target + // space and is moved by 25. + expected_visible_layer_rect = gfx::Rect(150, 50, 50, 150); + expected_drawable_content_rect = gfx::Rect(13, 38); + drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, - VisibleRectFor3dOrthographicIsNotClippedBehindSurface) { +TEST_F(LayerTreeHostCommonDrawRectsTest, + DrawRectsFor3dOrthographicIsNotClippedBehindSurface) { // There is currently no explicit concept of an orthographic projection plane // in our code (nor in the CSS spec to my knowledge). Therefore, layers that // are technically behind the surface in an orthographic world should not be @@ -2904,22 +2946,30 @@ layer_to_surface_transform.RotateAboutYAxis(45.0); layer_to_surface_transform.Translate(-50.0, 0.0); - gfx::Rect expected = gfx::Rect(0, 0, 100, 100); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + // Layer is rotated about Y Axis, and its width is 100/sqrt(2) in surface + // space. + gfx::Rect expected_visible_layer_rect = gfx::Rect(100, 100); + gfx::Rect expected_drawable_content_rect = gfx::Rect(14, 0, 72, 100); + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveWhenClippedByW) { - // Test the calculateVisibleRect() function works correctly when projecting a - // surface onto a layer, but the layer is partially behind the camera (not - // just behind the projection plane). In this case, the cartesian coordinates - // may seem to be valid, but actually they are not. The visible rect needs to - // be properly clipped by the w = 0 plane in homogeneous coordinates before - // converting to cartesian coordinates. +TEST_F(LayerTreeHostCommonDrawRectsTest, + DrawRectsFor3dPerspectiveWhenClippedByW) { + // Test visible layer rect and drawable content rect are calculated correctly + // when projecting a surface onto a layer, but the layer is partially behind + // the camera (not just behind the projection plane). In this case, the + // cartesian coordinates may seem to be valid, but actually they are not. The + // visible rect needs to be properly clipped by the w = 0 plane in homogeneous + // coordinates before converting to cartesian coordinates. The drawable + // content rect would be entire surface rect because layer is rotated at the + // camera position. - gfx::Rect target_surface_rect = gfx::Rect(-50, -50, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(-10, -1, 20, 2); + gfx::Rect target_surface_rect = gfx::Rect(0, 0, 200, 200); + gfx::Rect layer_content_rect = gfx::Rect(0, 0, 20, 2); gfx::Transform layer_to_surface_transform; // The layer is positioned so that the right half of the layer should be in @@ -2928,8 +2978,9 @@ // perspective and rotation about the center of the layer. layer_to_surface_transform.MakeIdentity(); layer_to_surface_transform.ApplyPerspectiveDepth(1.0); - layer_to_surface_transform.Translate3d(-2.0, 0.0, 1.0); - layer_to_surface_transform.RotateAboutYAxis(45.0); + layer_to_surface_transform.Translate3d(10.0, 0.0, 1.0); + layer_to_surface_transform.RotateAboutYAxis(-45.0); + layer_to_surface_transform.Translate(-10, -1); // Sanity check that this transform does indeed cause w < 0 when applying the // transform, otherwise this code is not testing the intended scenario. @@ -2939,15 +2990,16 @@ &clipped); ASSERT_TRUE(clipped); - int expected_x_position = 0; - int expected_width = 10; - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected_x_position, actual.x()); - EXPECT_EQ(expected_width, actual.width()); + gfx::Rect expected_visible_layer_rect = gfx::Rect(0, 1, 10, 1); + gfx::Rect expected_drawable_content_rect = target_surface_rect; + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, VisibleRectForPerspectiveUnprojection) { +TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsForPerspectiveUnprojection) { // To determine visible rect in layer space, there needs to be an // un-projection from surface space to layer space. When the original // transform was a perspective projection that was clipped, it returns a rect @@ -2956,14 +3008,16 @@ // This sequence of transforms causes one corner of the layer to protrude // across the w = 0 plane, and should be clipped. - gfx::Rect target_surface_rect = gfx::Rect(-50, -50, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(-10, -10, 20, 20); + gfx::Rect target_surface_rect = gfx::Rect(0, 0, 150, 150); + gfx::Rect layer_content_rect = gfx::Rect(0, 0, 20, 20); gfx::Transform layer_to_surface_transform; layer_to_surface_transform.MakeIdentity(); + layer_to_surface_transform.Translate(10, 10); layer_to_surface_transform.ApplyPerspectiveDepth(1.0); layer_to_surface_transform.Translate3d(0.0, 0.0, -5.0); layer_to_surface_transform.RotateAboutYAxis(45.0); layer_to_surface_transform.RotateAboutXAxis(80.0); + layer_to_surface_transform.Translate(-10, -10); // Sanity check that un-projection does indeed cause w < 0, otherwise this // code is not testing the intended scenario. @@ -2977,10 +3031,13 @@ // Only the corner of the layer is not visible on the surface because of being // clipped. But, the net result of rounding visible region to an axis-aligned // rect is that the entire layer should still be considered visible. - gfx::Rect expected = gfx::Rect(-10, -10, 20, 20); - gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( - target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_EQ(expected, actual); + gfx::Rect expected_visible_layer_rect = layer_content_rect; + gfx::Rect expected_drawable_content_rect = target_surface_rect; + LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( + target_surface_rect, layer_to_surface_transform, layer_content_rect); + EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); + EXPECT_EQ(expected_drawable_content_rect, + drawing_layer->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, @@ -9744,6 +9801,54 @@ child->mask_layer()->ScreenSpaceTransform()); } +TEST_F(LayerTreeHostCommonTest, + SublayerScaleWithTransformNodeBetweenTwoTargets) { + LayerImpl* root = root_layer(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(root); + LayerImpl* between_targets = AddChild<LayerImpl>(render_surface1); + LayerImpl* render_surface2 = AddChild<LayerImpl>(between_targets); + LayerImpl* test_layer = AddChild<LayerImpl>(render_surface2); + const gfx::Transform identity_matrix; + test_layer->SetDrawsContent(true); + + gfx::Transform scale; + scale.Scale(2.f, 2.f); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(render_surface1, scale, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(between_targets, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + SetLayerPropertiesForTesting(render_surface2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + // We want layer between the two targets to create a clip node and transform + // node but it shouldn't create a render surface. + between_targets->SetMasksToBounds(true); + between_targets->Set3dSortingContextId(2); + + ExecuteCalculateDrawProperties(root); + + TransformTree& tree = + root->layer_tree_impl()->property_trees()->transform_tree; + TransformNode* node = tree.Node(render_surface1->transform_tree_index()); + EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f)); + + node = tree.Node(between_targets->transform_tree_index()); + EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(1.f, 1.f)); + + node = tree.Node(render_surface2->transform_tree_index()); + EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f)); + + EXPECT_EQ(gfx::Rect(15, 15), test_layer->visible_layer_rect()); +} + TEST_F(LayerTreeHostCommonTest, LargeTransformTest) { LayerImpl* root = root_layer(); LayerImpl* render_surface1 = AddChild<LayerImpl>(root);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 5bfb96a..4f2f1e4 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1054,10 +1054,6 @@ if (input_handler_client_) input_handler_client_->ReconcileElasticOverscrollAndRootScroll(); - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Compositing.NumActiveLayers", - base::saturated_cast<int>(active_tree_->NumLayers()), 1, 400, 20); - if (const char* client_name = GetClientNameForMetrics()) { size_t total_picture_memory = 0; for (const PictureLayerImpl* layer : active_tree()->picture_layers()) @@ -1070,6 +1066,11 @@ client_name), base::saturated_cast<int>(total_picture_memory / 1024)); } + // GetClientNameForMetrics only returns one non-null value over the lifetime + // of the process, so this histogram name is runtime constant. + UMA_HISTOGRAM_CUSTOM_COUNTS( + base::StringPrintf("Compositing.%s.NumActiveLayers", client_name), + base::saturated_cast<int>(active_tree_->NumLayers()), 1, 400, 20); } bool update_lcd_text = false;
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index e41da4b4..9817125 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -834,6 +834,9 @@ "Compositing.%s.LayerTreeImpl.CalculateDrawPropertiesUs", client_name), timer.Elapsed().InMicroseconds()); + UMA_HISTOGRAM_COUNTS_100( + base::StringPrintf("Compositing.%s.NumRenderSurfaces", client_name), + base::saturated_cast<int>(render_surface_layer_list_.size())); } }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 4579edd..50214b89 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -261,41 +261,8 @@ # GYP: //chrome/chrome_tests.gypi:chrome_junit_tests junit_binary("chrome_junit_tests") { - java_files = [ - "junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java", - "junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java", - "junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java", - "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java", - "junit/src/org/chromium/chrome/browser/crash/LogcatExtractionCallableTest.java", - "junit/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtilsTest.java", - "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java", - "junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java", - "junit/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java", - "junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java", - "junit/src/org/chromium/chrome/browser/media/remote/MediaUrlResolverTest.java", - "junit/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfoTest.java", - "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterRouteTest.java", - "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterSinkObservationTest.java", - "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterTestBase.java", - "junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java", - "junit/src/org/chromium/chrome/browser/media/router/cast/DiscoveryCallbackTest.java", - "junit/src/org/chromium/chrome/browser/media/router/cast/JSONTestUtils.java", - "junit/src/org/chromium/chrome/browser/media/router/cast/TestUtils.java", - "junit/src/org/chromium/chrome/browser/notifications/NotificationUIManagerUnitTest.java", - "junit/src/org/chromium/chrome/browser/ntp/NativePageFactoryTest.java", - "junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java", - "junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java", - "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java", - "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java", - "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java", - "junit/src/org/chromium/chrome/browser/omaha/ResponseParserTest.java", - "junit/src/org/chromium/chrome/browser/omaha/VersionNumberTest.java", - "junit/src/org/chromium/chrome/browser/snackbar/SnackbarCollectionUnitTest.java", - "junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java", - "junit/src/org/chromium/chrome/browser/util/NonThreadSafeTest.java", - "junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java", - "junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java", - ] + # From java_sources.gni. + java_files = chrome_junit_test_java_sources deps = [ ":chrome_java", ":chrome_java_resources", @@ -569,19 +536,9 @@ android_library("chrome_sync_shell_test_apk_java") { testonly = true - java_files = [ - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java", - ] + + # From java_sources.jni. + java_files = sync_shell_test_java_sources deps = [ "//base:base_java",
diff --git a/chrome/android/OWNERS b/chrome/android/OWNERS index 7dd4fbab..792a9e471 100644 --- a/chrome/android/OWNERS +++ b/chrome/android/OWNERS
@@ -7,4 +7,4 @@ tedchoc@chromium.org yfriedman@chromium.org -per-file java_sources.gni=twellington@chromium.org +per-file java_sources.gni=*
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 2c78495..2394abe 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -465,7 +465,7 @@ <message name="IDS_CLEAR_BROWSING_DATA_PROGRESS_TITLE" desc='Title for the progress dialog used when waiting for "clear browsing data" to complete.'> Clearing browsing data </message> - <message name="IDS_CLEAR_DATA_DELETE" desc="Button that allows the user to clear their browsing data. [CHAR-LIMIT=20]"> + <message name="IDS_CLEAR_DATA_DELETE" desc="Button that allows the user to clear their browsing data. [CHAR-LIMIT=30]"> Clear data </message> <message name="IDS_CLEAR_BROWSING_DATA_PROGRESS_MESSAGE" desc='Message on the progress dialog used when waiting for "clear browsing data" to complete.'>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 84708ef..2dd3dab 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1185,3 +1185,53 @@ "javatests/src/org/chromium/chrome/test/util/ChromeSigninUtilsTest.java", "javatests/src/org/chromium/chrome/test/util/parameters/SigninParametersTest.java", ] + +chrome_junit_test_java_sources = [ + "junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java", + "junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java", + "junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java", + "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java", + "junit/src/org/chromium/chrome/browser/crash/LogcatExtractionCallableTest.java", + "junit/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtilsTest.java", + "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java", + "junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java", + "junit/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java", + "junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java", + "junit/src/org/chromium/chrome/browser/media/remote/MediaUrlResolverTest.java", + "junit/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfoTest.java", + "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterRouteTest.java", + "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterSinkObservationTest.java", + "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterTestBase.java", + "junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java", + "junit/src/org/chromium/chrome/browser/media/router/cast/DiscoveryCallbackTest.java", + "junit/src/org/chromium/chrome/browser/media/router/cast/JSONTestUtils.java", + "junit/src/org/chromium/chrome/browser/media/router/cast/TestUtils.java", + "junit/src/org/chromium/chrome/browser/notifications/NotificationUIManagerUnitTest.java", + "junit/src/org/chromium/chrome/browser/ntp/NativePageFactoryTest.java", + "junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java", + "junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java", + "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java", + "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java", + "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java", + "junit/src/org/chromium/chrome/browser/omaha/ResponseParserTest.java", + "junit/src/org/chromium/chrome/browser/omaha/VersionNumberTest.java", + "junit/src/org/chromium/chrome/browser/snackbar/SnackbarCollectionUnitTest.java", + "junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java", + "junit/src/org/chromium/chrome/browser/util/NonThreadSafeTest.java", + "junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java", + "junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java", +] + +sync_shell_test_java_sources = [ + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java", +]
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index e8bfe3d..723404c 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1254,11 +1254,11 @@ <message name="IDS_FLAGS_DISPLAY_COLOR_CALIBRATION_DESCRIPTION" desc="Description for the flag for the color calibration of the display."> Allow color calibration of the display if the display supports the feature. </message> - <message name="IDS_FLAGS_ENABLE_QUIRKS_CLIENT_NAME" desc="Name for the flag to enable the Quirks Client for calibration of the display and other hardware."> - Enable Quirks Client for display calibration. + <message name="IDS_FLAGS_DISABLE_QUIRKS_CLIENT_NAME" desc="Name for the flag to disable the Quirks Client for calibration of the display and other hardware."> + Disable Quirks Client for display calibration. </message> - <message name="IDS_FLAGS_ENABLE_QUIRKS_CLIENT_DESCRIPTION" desc="Description for the flag to enable the Quirks Client for calibration of the display and other hardware."> - Enable retrieval of icc display files from Quirks Server for display color calibration. + <message name="IDS_FLAGS_DISABLE_QUIRKS_CLIENT_DESCRIPTION" desc="Description for the flag to disable the Quirks Client for calibration of the display and other hardware."> + Disable retrieval of icc display files from Quirks Server for display color calibration. </message> <message name="IDS_FLAGS_MEMORY_PRESSURE_THRESHOLD_NAME" desc="Name for the flag which specifies which memory pressure strategy should be used on ChromeOS."> Memory discard strategy for advanced pressure handling
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 906ab3c..39b7e10 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -5780,6 +5780,12 @@ <message name="IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION" desc="Description for the flag to enable experimental Web Platform features."> Enables experimental Web Platform features that are in development. </message> + <message name="IDS_FLAGS_EXPERIMENTAL_POINTER_EVENT_NAME" desc="Name for the flag to enable the experimental pointer events."> + Pointer Events + </message> + <message name="IDS_FLAGS_EXPERIMENTAL_POINTER_EVENT_DESCRIPTION" desc="Description for the flag to enable the experimental pointer events."> + Enables partial experimental support for the Pointer Events API. This is intended only for testing by web developers, it will cause some websites to be subtly broken. + </message> <message name="IDS_FLAGS_EXPERIMENTAL_FRAMEWORK_NAME" desc="Name for the flag to enable the Experimental Framework."> Experimental Framework. </message> @@ -11652,6 +11658,9 @@ <message name="IDS_NOTIFICATION_BUTTON_CLOSE" desc="Button label to close a notification"> Close </message> + <message name="IDS_NOTIFICATION_BUTTON_OPTIONS" desc="Button label to display more options like extra buttons or going to the site settings page."> + Options + </message> <message name="IDS_NOTIFICATION_SETTINGS" desc="Button label to go to the notification settings panel"> Notification settings </message> @@ -12922,7 +12931,7 @@ Sorry, your password could not be verified because you are offline. </message> <message name="IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT" desc="Text to display in the password field for user pod when no password has been entered."> - Enter password + Password </message> <message name="IDS_LOGIN_POD_SIGNING_IN" desc="Text to display at the bottom of a user pod during signing in the user. The translation should be as short as possible because of limited UI space."> Signing in @@ -12973,19 +12982,19 @@ </message> <message name="IDS_LOGIN_POD_USER_REMOVE_WARNING_SYNC" desc="Main text shown as a warning when attempting to remove an user. This case is for synced profiles, with all statistics loaded correctly. The symbol $1 will be substituted with custom JS code, so it should not be replaced by a #."> {NUM_ITEMS, plural, - =1 {This will permanently delete $1 item from this device but will not clear synced items from other devices.} - other {This will permanently delete $1 items from this device but will not clear synced items from other devices.}} + =1 {This will permanently delete $1 item from this device. To retrieve your data later, sign in to chrome as $2.} + other {This will permanently delete $1 items from this device. To retrieve your data later, sign in to chrome as $2.}} </message> <message name="IDS_LOGIN_POD_USER_REMOVE_WARNING_SYNC_WITH_ERRORS" desc="Main text shown as a warning when attempting to remove an user. This case is for non-synced profiles, with some statistics failed to load. The symbol $1 will be substituted with custom JS code, so it should not be replaced by a #."> {NUM_ITEMS, plural, - =1 {This will permanently delete at least $1 item from this device but will not clear synced items from other devices.} - other {This will permanently delete at least $1 items from this device but will not clear synced items from other devices.}} + =1 {This will permanently delete at least $1 item from this device. To retrieve your data later, sign in to chrome as $2.} + other {This will permanently delete at least $1 items from this device. To retrieve your data later, sign in to chrome as $2.}} </message> <message name="IDS_LOGIN_POD_USER_REMOVE_WARNING_SYNC_NOSTATS" desc="Main text shown as a warning when attempting to remove an user. This case is for synced profiles with statistics unavailable. (Possible case: Chromium decided not to load the statistics of closed profiles.)"> - This will permanently delete your browsing data from this device but will not clear synced items from other devices. + This will permanently delete your browsing data from this device. To retrieve your data later, sign in to chrome as $2. </message> <message name="IDS_LOGIN_POD_USER_REMOVE_WARNING_SYNC_CALCULATING" desc="Main text shown as a warning when attempting to remove an user. This case is for synced profiles when the statistics is still loading. $1 is always replaced by localized version of the ellipsis (...)."> - This will permanently delete at least <ph name="TOTAL_COUNT">$1<ex>...</ex></ph> items from this device but will not clear synced items from other devices. + This will permanently delete at least <ph name="TOTAL_COUNT">$1<ex>...</ex></ph> items from this device. To retrieve your data later, sign in to chrome as $2. </message> </if> @@ -14302,7 +14311,6 @@ <message name="IDS_FLAGS_TOUCH_HOVER_DESCRIPTION" desc="Description of the 'Enable support for hover capable touchscreens' flag."> Enables hover feature by holding your finger just over the screen to experience a mouseover event. </message> - <message name="IDS_ALLOW_INSECURE_LOCALHOST" desc="Name of the 'Allow insecure localhost' flag."> Allow invalid certificates for resources loaded from localhost. </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 39ca6ce..13471af 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -827,9 +827,9 @@ ui::switches::kDisableDisplayColorCalibration), }, { - "enable-quirks-client", IDS_FLAGS_ENABLE_QUIRKS_CLIENT_NAME, - IDS_FLAGS_ENABLE_QUIRKS_CLIENT_DESCRIPTION, kOsCrOS, - SINGLE_VALUE_TYPE(quirks::switches::kEnableQuirksClient), + "disable-quirks-client", IDS_FLAGS_DISABLE_QUIRKS_CLIENT_NAME, + IDS_FLAGS_DISABLE_QUIRKS_CLIENT_DESCRIPTION, kOsCrOS, + SINGLE_VALUE_TYPE(quirks::switches::kDisableQuirksClient), }, { "ash-disable-screen-orientation-lock", @@ -1819,6 +1819,11 @@ IDS_FLAGS_MEDIA_STYLE_NOTIFICATION_DESCRIPTION, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kMediaStyleNotification)}, #endif + {"enable-pointer-events", // FLAGS:RECORD_UMA + IDS_FLAGS_EXPERIMENTAL_POINTER_EVENT_NAME, + IDS_FLAGS_EXPERIMENTAL_POINTER_EVENT_DESCRIPTION, + kOsAll, + FEATURE_VALUE_TYPE(features::kPointerEvents)}, // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index fd2692d..adaaf16b 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -141,7 +141,10 @@ ] if (use_x11) { configs += [ "//build/config/linux:x11" ] - deps += [ "//ui/events/devices" ] + deps += [ + "//ui/events/devices", + "//ui/events/devices/x11", + ] sources -= [ "system/input_device_settings_impl_ozone.cc", "system_logs/touch_log_source_ozone.cc",
diff --git a/chrome/browser/chromeos/display/quirks_browsertest.cc b/chrome/browser/chromeos/display/quirks_browsertest.cc index bd1489d..ed64aaa 100644 --- a/chrome/browser/chromeos/display/quirks_browsertest.cc +++ b/chrome/browser/chromeos/display/quirks_browsertest.cc
@@ -2,13 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/command_line.h" #include "base/files/file_util.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/quirks/quirks_manager.h" -#include "components/quirks/switches.h" #include "content/public/test/test_utils.h" #include "net/url_request/test_url_fetcher_factory.h" @@ -83,11 +81,6 @@ end_message_loop_.Run(); } - // InProcessBrowserTest overrides. - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch(switches::kEnableQuirksClient); - } - void SetUpOnMainThread() override { // NOTE: QuirksManager::Initialize() isn't necessary here, since it'll be // called in ChromeBrowserMainPartsChromeos::PreMainMessageLoopRun().
diff --git a/chrome/browser/chromeos/policy/device_quirks_policy_browsertest.cc b/chrome/browser/chromeos/policy/device_quirks_policy_browsertest.cc index 265b003..e7097e05 100644 --- a/chrome/browser/chromeos/policy/device_quirks_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_quirks_policy_browsertest.cc
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/command_line.h" #include "base/files/file_util.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" @@ -10,7 +9,6 @@ #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "components/quirks/quirks_manager.h" -#include "components/quirks/switches.h" #include "content/public/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -24,10 +22,6 @@ public: DeviceQuirksPolicyTest() {} - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch(quirks::switches::kEnableQuirksClient); - } - void SetUpInProcessBrowserTestFixture() override { InstallOwnerKey(); DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
diff --git a/chrome/browser/notifications/notification_ui_manager_mac.mm b/chrome/browser/notifications/notification_ui_manager_mac.mm index 74023f7..ef595dbf 100644 --- a/chrome/browser/notifications/notification_ui_manager_mac.mm +++ b/chrome/browser/notifications/notification_ui_manager_mac.mm
@@ -147,8 +147,8 @@ DCHECK( [toast respondsToSelector:@selector(_alternateActionButtonTitles)]); - // utf8 ellipsis: - [toast setActionButtonTitle:@"\u2026"]; + [toast setActionButtonTitle:l10n_util::GetNSString( + IDS_NOTIFICATION_BUTTON_OPTIONS)]; [toast setValue:@YES forKey:@"_alwaysShowAlternateActionMenu"];
diff --git a/chrome/browser/resources/md_user_manager/user_manager.js b/chrome/browser/resources/md_user_manager/user_manager.js index caaf404f..6864f2c 100644 --- a/chrome/browser/resources/md_user_manager/user_manager.js +++ b/chrome/browser/resources/md_user_manager/user_manager.js
@@ -6,6 +6,7 @@ <include src="../../../../ui/login/bubble.js"> <include src="../../../../ui/login/login_ui_tools.js"> <include src="../../../../ui/login/display_manager.js"> +<include src="../../../../ui/login/account_picker/user_pod_template.js"> <include src="../../../../ui/login/account_picker/screen_account_picker.js"> <include src="../../../../ui/login/account_picker/user_pod_row.js"> @@ -14,6 +15,13 @@ var DisplayManager = cr.ui.login.DisplayManager; /** + * Maximum possible height of the #login-header-bar, including the padding + * and the border. + * @const {number} + */ + var MAX_LOGIN_HEADER_BAR_HEIGHT = 57; + + /** * Manages initialization of screens, transitions, and error messages. * @constructor * @extends {DisplayManager} @@ -24,6 +32,28 @@ UserManager.prototype = { __proto__: DisplayManager.prototype, + + /** + * Indicates that this is the Material Design Desktop User Manager. + * @type {boolean} + */ + newDesktopUserManager: true, + + /** + * @override + * Overrides clientAreaSize in DisplayManager. When a new profile is created + * the #outer-container page may not be visible yet, so user-pods cannot be + * placed correctly. Therefore, we use dimensions of the #animated-pages. + * @type {{width: number, height: number}} + */ + get clientAreaSize() { + var userManagerPages = document.querySelector('user-manager-pages'); + var width = userManagerPages.offsetWidth; + // Deduct the maximum possible height of the #login-header-bar from the + // height of #animated-pages. Result is the remaining visible height. + var height = userManagerPages.offsetHeight - MAX_LOGIN_HEADER_BAR_HEIGHT; + return {width: width, height: height}; + } }; /**
diff --git a/chrome/browser/resources/md_user_manager/user_manager_styles.html b/chrome/browser/resources/md_user_manager/user_manager_styles.html index 7b0785b..200aad4 100644 --- a/chrome/browser/resources/md_user_manager/user_manager_styles.html +++ b/chrome/browser/resources/md_user_manager/user_manager_styles.html
@@ -4,10 +4,10 @@ <template> <style include="shared-styles"> body { - background-color: #eee; + background-color: var(--paper-grey-200); } - /* Overrides for the desktop user manager screen. */ + user-manager-pages, #login-header-bar { bottom: 0; left: 0; @@ -15,8 +15,24 @@ right: 0; } + user-manager-pages { + top: 0; + } + + #login-header-bar.shadow { + box-shadow: 0 -1px 3px rgba(0, 0, 0, .2); + } + + /* Overrides src/ui/login/screen_container.css for the desktop user + * manager. */ + #outer-container { min-height: 0; + overflow-x: hidden; + overflow-y: auto; + padding-bottom: 40px; + padding-top: 40px; + z-index: initial; } .bubble.faded { @@ -24,193 +40,235 @@ } .pod { - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); - height: 226px; - /* On non-retina desktop, the text is blurry if we use the scale3d() - inherited from user_pod_row.js */ - transform: scale(0.9); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .24), + 0 0 2px 0 rgba(0, 0, 0, .12); + color: var(--paper-grey-800); + cursor: default; + height: auto; + transform: none; + width: auto; } - podrow[ncolumns='6'] .pod { - transform: scale(0.8); - } - - /* Because of crbug.com/406529, the text in the .name div is janky if there's - both a transform:scale and a transition:opacity applied to a div, so we must - apply the opacity change to the children instead. */ .pod.faded { opacity: 1; } - .pod.faded .user-image-pane, - .pod.faded .main-pane { - opacity: .4; - } - - .pod.hovered:not(.focused) { - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - } - - .pod.focused { - box-shadow: 0 16px 21px rgba(0, 0, 0, 0.2); - transform: scale(1) !important; + .pod.focused, + .pod.hovered { + box-shadow: 0 10px 10px 0 rgba(0, 0, 0, .26), + 0 14px 28px 0 rgba(0, 0, 0, .25); } .pod.focused.locked { - box-shadow: 0 12px 21px rgba(0, 0, 0, 0.2); - height: 220px; + box-shadow: 0 12px 21px rgba(0, 0, 0, .2); + height: auto; } - .user-image-pane { + .pod .user-image-pane { border-top-left-radius: 2px; border-top-right-radius: 2px; - height: 180px; - left: 0; - top: 0; - width: 180px; - } - - html[dir=rtl] .user-image-pane { - right: 0; - } - - .pod .name { - margin-top: 12px; + position: static; } .pod .user-image { - height: 180px; - width: 180px; + height: 160px; + width: 160px; } - .pod input[type='password'] { - height: 45px; /* 1px shorter as to not overlap the pod's rounded corners */ - top: 1px; + .pod .main-pane { + line-height: 20px; + padding: 10px; + position: static; + } + + .pod .main-pane .name-container { + display: block; + position: static; + width: auto; + } + + .pod .main-pane .name-container .name { + color: inherit; + font-size: inherit; + margin: 0; + padding: 0; + text-align: initial; + width: 118px; } .pod .indicator-container { - background-color: rgba(255, 255, 255, 0.85); - border-radius: 16px; - height: 32px; - left: 8px; - position: absolute; - top: 8px; - } - - html[dir=rtl] .pod .indicators { + background-color: rgba(255, 255, 255, .85); + border-radius: 0; + bottom: 10px; + height: 20px; left: auto; - right: 8px; + position: absolute; + right: 10px; + top: auto; + width: 20px; } - .pod .indicator { + html[dir='rtl'] .pod .indicator-container { + left: 10px; + right: auto; + } + + /* Using -webkit-mask on the indicators allows us to tweak the color. */ + .pod .indicator-container > .indicator { + -webkit-mask-position: center; + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 20px; + background-color: var(--paper-grey-600); background-position: center; background-repeat: no-repeat; background-size: 18px; display: none; float: left; - height: 32px; - width: 32px; - } - - /* Using -webkit-mask on the indicators allows us to tweak the color. */ - .pod .indicator-container > div { - -webkit-mask-position: center; - -webkit-mask-repeat: no-repeat; - -webkit-mask-size: 24px; + height: 20px; + width: 20px; } .pod.locked .locked-indicator { -webkit-mask-image: url(../../../../ui/webui/resources/images/lock.svg); - background-color: var(--paper-grey-600); display: initial; } .pod.legacy-supervised .legacy-supervised-indicator { -webkit-mask-image: url(../../../../ui/webui/resources/images/supervisor_account.svg); - background-color: var(--google-blue-500); display: initial; } .pod.child .child-indicator { -webkit-mask-image: url(../../../../ui/webui/resources/images/account_child_invert.svg); - background-color: var(--google-blue-500); display: initial; } - .main-pane { - left: 0; + .action-box-area:focus ~ .user-image-gradient-area, + .action-box-area.hovered ~ .user-image-gradient-area { + background-image: linear-gradient(rgba(0, 0, 0, .4), transparent 100%); + display: initial; + height: 56px; + position: absolute; top: 0; + width: 100%; } - html[dir=rtl] .main-pane { - right: 0; + .action-box-area { + background-color: transparent; } - .name-container, - .pod.focused:not(.multiprofiles-policy-applied) .auth-container { - top: 180px; - width: 180px; + .action-box-area.menu-moved-up { + transform: none; } - .pod.focused:not(.locked) .name-container { - display: block; + .action-box-area .action-box-button { + display: none; } - .pod .name { - color: var(--paper-grey-800); - font-size: 15px; - margin-top: 11px; + .action-box-area .action-box-icon { + color: white; + display: inline-flex; + margin-top: 4px; } .pod.focused:not(.locked) .auth-container { display: none; } - .pod[auth-type='offlinePassword'].focused.locked .password-entry-container { - display: flex; - flex: auto; + .pod.focused:not(.multiprofiles-policy-applied) .auth-container { + left: 0; } - .action-box-area { - background-color: var(--google-grey-100); - height: 24px; - /* Because of crbug.com/406529, the text in the .name div is janky if there's - an opacity transition in this div. */ - transition: none; - width: 24px; + .pod .auth-container input[type='password'] { + line-height: inherit; + padding: 10px; + top: 0; + width: 140px; } - .action-box-button, - .action-box-button:hover, - .action-box-area.active .action-box-button { - background-image: none; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #989898; - height: 0; - left: 6px; + .pod .auth-container input[type='password']:focus { + outline: 0; + } + + .pod[auth-type='onlineSignIn'] .reauth-hint-container { margin: 0; - position: absolute; - top: 9px; - width: 0; + padding: 10px 0; } - .action-box-button:hover, + .reauth-hint-container .reauth-warning { + height: 20px; + width: 20px; + } + + .reauth-hint-container .reauth-name-hint { + color: inherit; + font-size: inherit; + } + .action-box-area.active .action-box-button { - border-top: 6px solid #4c4c4c; + display: none; + } + + .action-box-area.active ~ .action-box-menu:not(.menu-moved-up) { + top: 8px; + } + + .action-box-area.active ~ .action-box-menu { + border: none; + box-shadow: 0 10px 20px 0 rgba(0, 0, 0, .19); + right: 8px; + width: 224px; + } + + html[dir=rtl] .action-box-area.active ~ .action-box-menu { + left: 8px; + right: auto; + } + + .action-box-menu-title { + color: inherit; + padding: 16px 12px; + } + + .action-box-menu-title-name, + .action-box-menu-title-email { + height: auto; + } + + .action-box-menu-title-email { + color: var(--paper-grey-600); + } + + .action-box-menu-remove { + border-top: 1px solid rgba(0, 0, 0, .12); + line-height: 32px; + padding: 8px 12px; + } + + .action-box-remove-user-warning { + border-top: 1px solid rgba(0, 0, 0, .12); + font-size: inherit; + line-height: 20px; + padding: 12px; + text-align: center; + } + + .action-box-remove-user-warning > * { + text-align: initial; + word-wrap: break-word; + } + + .total-count, + .pod:not(.synced) .action-box-remove-user-warning-text { + font-weight: 500; } .action-box-remove-user-warning .remove-warning-button { - height: 30px; - } - - .action-box-remove-user-warning .remove-warning-button:focus { - /* Override the default blue border inherited from - button.custom-appearance:focus. */ - border: 1px solid transparent !important; - box-shadow: inset 0 0 0 1px #fff; + background: var(--google-red-700); + min-width: 72px; + width: auto; } </style> </template>
diff --git a/chrome/browser/resources/user_manager/user_manager.css b/chrome/browser/resources/user_manager/user_manager.css index eb3801f..3b76f2f 100644 --- a/chrome/browser/resources/user_manager/user_manager.css +++ b/chrome/browser/resources/user_manager/user_manager.css
@@ -199,10 +199,3 @@ .action-box-remove-user-warning .remove-warning-button { height: 30px; } - -.action-box-remove-user-warning .remove-warning-button:focus { - /* Override the default blue border inherited from - button.custom-appearance:focus. */ - border: 1px solid transparent !important; - box-shadow: inset 0 0 0 1px #fff; -}
diff --git a/chrome/browser/resources/user_manager/user_manager.js b/chrome/browser/resources/user_manager/user_manager.js index 96ddf65..86c7ac8 100644 --- a/chrome/browser/resources/user_manager/user_manager.js +++ b/chrome/browser/resources/user_manager/user_manager.js
@@ -6,6 +6,7 @@ <include src="../../../../ui/login/login_ui_tools.js"> <include src="../../../../ui/login/display_manager.js"> <include src="control_bar.js"> +<include src="../../../../ui/login/account_picker/user_pod_template.js"> <include src="../../../../ui/login/account_picker/screen_account_picker.js"> <include src="../../../../ui/login/account_picker/user_pod_row.js"> <include src="../../../../ui/login/resource_loader.js">
diff --git a/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js index cf1c0e7..7dcf876 100644 --- a/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js +++ b/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js
@@ -312,7 +312,8 @@ }.bind(this)); }); -TEST_F('BluetoothWebUITestAsync', 'testForget', function() { +// TODO(crbug.com/605090): Disabled because of flakiness. +TEST_F('BluetoothWebUITestAsync', 'DISABLED_testForget', function() { assertEquals(this.browsePreload, document.location.href); // Enable bluetooth.
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 69f8e8e..a8690ab 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -3292,6 +3292,7 @@ '../build/linux/system.gyp:x11', '../build/linux/system.gyp:gio', '../ui/events/devices/events_devices.gyp:events_devices', + '../ui/events/devices/x11/events_devices_x11.gyp:events_devices_x11', ], }], ['use_udev==1', {
diff --git a/chrome/chrome_gpu.gypi b/chrome/chrome_gpu.gypi index 3241e11..3d153e3 100644 --- a/chrome/chrome_gpu.gypi +++ b/chrome/chrome_gpu.gypi
@@ -26,6 +26,8 @@ '../components/components.gyp:arc_mojo_bindings', ], 'sources': [ + 'gpu/arc_gpu_video_decode_accelerator.cc', + 'gpu/arc_gpu_video_decode_accelerator.h', 'gpu/arc_video_accelerator.h', 'gpu/gpu_arc_video_service.cc', 'gpu/gpu_arc_video_service.h',
diff --git a/chrome/common/OWNERS b/chrome/common/OWNERS index 0d1d0612..849bf4d8 100644 --- a/chrome/common/OWNERS +++ b/chrome/common/OWNERS
@@ -37,6 +37,7 @@ # Instant/Search files. per-file instant_types*=file://chrome/browser/search/OWNERS per-file search_types.*=file://chrome/browser/search/OWNERS +per-file search_urls*=file://chrome/browser/search/OWNERS #Content settings per-file content_settings*=markusheintz@chromium.org
diff --git a/chrome/common/search_urls.h b/chrome/common/search_urls.h index c4bbacd..8840b5f2 100644 --- a/chrome/common/search_urls.h +++ b/chrome/common/search_urls.h
@@ -9,7 +9,11 @@ namespace search { -// Returns true if |my_url| matches |other_url|. +// Returns true if |my_url| matches |other_url| in terms of origin (i.e. host, +// port, and scheme) and path. As a special case, this also matches if |my_url| +// is "https://" and |other_url| is "http://" (and host, port, and path match). +// This is so that "https://" URLs will be considered "Instant URLs" even if the +// default search provider URL is "http://". bool MatchesOriginAndPath(const GURL& my_url, const GURL& other_url); } // namespace search
diff --git a/chrome/gpu/BUILD.gn b/chrome/gpu/BUILD.gn index 8ce64935..384b4186 100644 --- a/chrome/gpu/BUILD.gn +++ b/chrome/gpu/BUILD.gn
@@ -16,6 +16,8 @@ if (is_chromeos) { deps += [ "//components/arc:arc_bindings" ] sources += [ + "arc_gpu_video_decode_accelerator.cc", + "arc_gpu_video_decode_accelerator.h", "arc_video_accelerator.h", "gpu_arc_video_service.cc", "gpu_arc_video_service.h",
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.cc b/chrome/gpu/arc_gpu_video_decode_accelerator.cc new file mode 100644 index 0000000..a2700b1e --- /dev/null +++ b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
@@ -0,0 +1,425 @@ +// Copyright 2016 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/callback_helpers.h" +#include "base/logging.h" +#include "base/run_loop.h" +#include "chrome/gpu/arc_gpu_video_decode_accelerator.h" +#include "content/public/gpu/gpu_video_decode_accelerator_factory.h" +#include "media/base/video_frame.h" + +namespace chromeos { +namespace arc { + +ArcGpuVideoDecodeAccelerator::InputRecord::InputRecord( + int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp) + : bitstream_buffer_id(bitstream_buffer_id), + buffer_index(buffer_index), + timestamp(timestamp) {} + +ArcGpuVideoDecodeAccelerator::InputBufferInfo::InputBufferInfo() + : offset(0), length(0) {} + +ArcGpuVideoDecodeAccelerator::InputBufferInfo::InputBufferInfo( + InputBufferInfo&& other) + : handle(std::move(other.handle)), + offset(other.offset), + length(other.length) {} + +ArcGpuVideoDecodeAccelerator::InputBufferInfo::~InputBufferInfo() {} + +ArcGpuVideoDecodeAccelerator::ArcGpuVideoDecodeAccelerator() + : pending_eos_output_buffer_(false), + arc_client_(nullptr), + next_bitstream_buffer_id_(0), + output_buffer_size_(0) {} + +ArcGpuVideoDecodeAccelerator::~ArcGpuVideoDecodeAccelerator() {} + +namespace { + +// An arbitrary chosen limit of the number of buffers. The number of +// buffers used is requested from the untrusted client side. +const size_t kMaxBufferCount = 128; + +} // anonymous namespace + +bool ArcGpuVideoDecodeAccelerator::Initialize( + const Config& config, + ArcVideoAccelerator::Client* client) { + DVLOG(5) << "Initialize(device=" << config.device_type + << ", input_pixel_format=" << config.input_pixel_format + << ", num_input_buffers=" << config.num_input_buffers << ")"; + DCHECK(thread_checker_.CalledOnValidThread()); + if (config.device_type != Config::DEVICE_DECODER) + return false; + DCHECK(client); + + if (arc_client_) { + DLOG(ERROR) << "Re-Initialize() is not allowed"; + return false; + } + + arc_client_ = client; + + if (config.num_input_buffers > kMaxBufferCount) { + DLOG(ERROR) << "Request too many buffers: " << config.num_input_buffers; + return false; + } + input_buffer_info_.resize(config.num_input_buffers); + + media::VideoDecodeAccelerator::Config vda_config; + switch (config.input_pixel_format) { + case HAL_PIXEL_FORMAT_H264: + vda_config.profile = media::H264PROFILE_MAIN; + break; + case HAL_PIXEL_FORMAT_VP8: + vda_config.profile = media::VP8PROFILE_ANY; + break; + default: + DLOG(ERROR) << "Unsupported input format: " << config.input_pixel_format; + return false; + } + vda_config.output_mode = + media::VideoDecodeAccelerator::Config::OutputMode::IMPORT; + + scoped_ptr<content::GpuVideoDecodeAcceleratorFactory> vda_factory = + content::GpuVideoDecodeAcceleratorFactory::CreateWithNoGL(); + vda_ = vda_factory->CreateVDA(this, vda_config); + if (!vda_) { + DLOG(ERROR) << "Failed to create VDA."; + return false; + } + return true; +} + +void ArcGpuVideoDecodeAccelerator::SetNumberOfOutputBuffers(size_t number) { + DVLOG(5) << "SetNumberOfOutputBuffers(" << number << ")"; + DCHECK(thread_checker_.CalledOnValidThread()); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + + if (number > kMaxBufferCount) { + DLOG(ERROR) << "Too many buffers: " << number; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + + std::vector<media::PictureBuffer> buffers; + for (size_t id = 0; id < number; ++id) { + media::PictureBuffer::TextureIds texture_ids; + texture_ids.push_back(0); + + // TODO(owenlin): Make sure the |coded_size| is what we want. + buffers.push_back(media::PictureBuffer(base::checked_cast<int32_t>(id), + coded_size_, texture_ids)); + } + vda_->AssignPictureBuffers(buffers); + + buffers_pending_import_.clear(); + buffers_pending_import_.resize(number); +} + +void ArcGpuVideoDecodeAccelerator::BindSharedMemory(PortType port, + uint32_t index, + base::ScopedFD ashmem_fd, + off_t offset, + size_t length) { + DVLOG(5) << "ArcGVDA::BindSharedMemory, offset: " << offset + << ", length: " << length; + DCHECK(thread_checker_.CalledOnValidThread()); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + + if (port != PORT_INPUT) { + DLOG(ERROR) << "SharedBuffer is only supported for input"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + InputBufferInfo* input_info = &input_buffer_info_[index]; + input_info->handle = std::move(ashmem_fd); + input_info->offset = offset; + input_info->length = length; +} + +void ArcGpuVideoDecodeAccelerator::BindDmabuf(PortType port, + uint32_t index, + base::ScopedFD dmabuf_fd) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + + if (port != PORT_OUTPUT) { + DLOG(ERROR) << "Dmabuf is only supported for input"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + buffers_pending_import_[index] = std::move(dmabuf_fd); +} + +void ArcGpuVideoDecodeAccelerator::UseBuffer(PortType port, + uint32_t index, + const BufferMetadata& metadata) { + DVLOG(5) << "UseBuffer(port=" << port << ", index=" << index + << ", metadata=(bytes_used=" << metadata.bytes_used + << ", timestamp=" << metadata.timestamp << ")"; + DCHECK(thread_checker_.CalledOnValidThread()); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + switch (port) { + case PORT_INPUT: { + InputBufferInfo* input_info = &input_buffer_info_[index]; + int32_t bitstream_buffer_id = next_bitstream_buffer_id_; + // Mask against 30 bits, to avoid (undefined) wraparound on signed + // integer. + next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; + int dup_fd = HANDLE_EINTR(dup(input_info->handle.get())); + if (dup_fd < 0) { + DLOG(ERROR) << "dup() failed."; + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + CreateInputRecord(bitstream_buffer_id, index, metadata.timestamp); + vda_->Decode(media::BitstreamBuffer( + bitstream_buffer_id, base::SharedMemoryHandle(dup_fd, true), + metadata.bytes_used, input_info->offset)); + if (metadata.flags & BUFFER_FLAG_EOS) { + vda_->Flush(); + } + break; + } + case PORT_OUTPUT: { + SendEosIfNeededOrReusePicture(index); + break; + } + default: + NOTREACHED(); + } +} + +void ArcGpuVideoDecodeAccelerator::Reset() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + vda_->Reset(); +} + +void ArcGpuVideoDecodeAccelerator::ProvidePictureBuffers( + uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, + const gfx::Size& dimensions, + uint32_t texture_target) { + DVLOG(5) << "ProvidePictureBuffers(" + << "requested_num_of_buffers=" << requested_num_of_buffers + << ", dimensions=" << dimensions.ToString() << ")"; + DCHECK(thread_checker_.CalledOnValidThread()); + coded_size_ = dimensions; + + VideoFormat video_format; + media::VideoPixelFormat output_format = vda_->GetOutputFormat(); + switch (output_format) { + case media::PIXEL_FORMAT_I420: + case media::PIXEL_FORMAT_YV12: + case media::PIXEL_FORMAT_NV12: + case media::PIXEL_FORMAT_NV21: + // HAL_PIXEL_FORMAT_YCbCr_420_888 is the flexible pixel format in Android + // which handles all 420 formats, with both orderings of chroma (CbCr and + // CrCb) as well as planar and semi-planar layouts. + video_format.pixel_format = HAL_PIXEL_FORMAT_YCbCr_420_888; + break; + default: + DLOG(ERROR) << "Format not supported: " << output_format; + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + video_format.buffer_size = + media::VideoFrame::AllocationSize(output_format, coded_size_); + output_buffer_size_ = video_format.buffer_size; + video_format.min_num_buffers = requested_num_of_buffers; + video_format.coded_width = dimensions.width(); + video_format.coded_height = dimensions.height(); + // TODO(owenlin): How to get visible size? + video_format.crop_top = 0; + video_format.crop_left = 0; + video_format.crop_width = dimensions.width(); + video_format.crop_height = dimensions.height(); + arc_client_->OnOutputFormatChanged(video_format); +} + +void ArcGpuVideoDecodeAccelerator::DismissPictureBuffer( + int32_t picture_buffer) { + // no-op +} + +void ArcGpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) { + DVLOG(5) << "PictureReady(picture_buffer_id=" << picture.picture_buffer_id() + << ", bitstream_buffer_id=" << picture.bitstream_buffer_id(); + DCHECK(thread_checker_.CalledOnValidThread()); + + // Empty buffer, returned in Flushing. + if (picture.bitstream_buffer_id() == -1) { + buffers_pending_eos_.push(picture.picture_buffer_id()); + return; + } + InputRecord* input_record = FindInputRecord(picture.bitstream_buffer_id()); + if (input_record == nullptr) { + DLOG(ERROR) << "Cannot find for bitstream buffer id: " + << picture.bitstream_buffer_id(); + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + + BufferMetadata metadata; + metadata.timestamp = input_record->timestamp; + metadata.bytes_used = output_buffer_size_; + arc_client_->OnBufferDone(PORT_OUTPUT, picture.picture_buffer_id(), metadata); +} + +void ArcGpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( + int32_t bitstream_buffer_id) { + DVLOG(5) << "NotifyEndOfBitstreamBuffer(" << bitstream_buffer_id << ")"; + DCHECK(thread_checker_.CalledOnValidThread()); + InputRecord* input_record = FindInputRecord(bitstream_buffer_id); + if (input_record == nullptr) { + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + arc_client_->OnBufferDone(PORT_INPUT, input_record->buffer_index, + BufferMetadata()); +} + +void ArcGpuVideoDecodeAccelerator::NotifyFlushDone() { + DCHECK(thread_checker_.CalledOnValidThread()); + pending_eos_output_buffer_ = true; + while (!buffers_pending_eos_.empty()) { + SendEosIfNeededOrReusePicture(buffers_pending_eos_.front()); + buffers_pending_eos_.pop(); + } +} + +void ArcGpuVideoDecodeAccelerator::NotifyResetDone() { + DCHECK(thread_checker_.CalledOnValidThread()); + arc_client_->OnResetDone(); +} + +static ArcVideoAccelerator::Error ConvertErrorCode( + media::VideoDecodeAccelerator::Error error) { + switch (error) { + case media::VideoDecodeAccelerator::ILLEGAL_STATE: + return ArcVideoAccelerator::ILLEGAL_STATE; + case media::VideoDecodeAccelerator::INVALID_ARGUMENT: + return ArcVideoAccelerator::INVALID_ARGUMENT; + case media::VideoDecodeAccelerator::UNREADABLE_INPUT: + return ArcVideoAccelerator::UNREADABLE_INPUT; + case media::VideoDecodeAccelerator::PLATFORM_FAILURE: + return ArcVideoAccelerator::PLATFORM_FAILURE; + default: + DLOG(ERROR) << "Unknown error: " << error; + return ArcVideoAccelerator::PLATFORM_FAILURE; + } +} + +void ArcGpuVideoDecodeAccelerator::NotifyError( + media::VideoDecodeAccelerator::Error error) { + DCHECK(thread_checker_.CalledOnValidThread()); + DLOG(ERROR) << "Error notified: " << error; + arc_client_->OnError(ConvertErrorCode(error)); +} + +void ArcGpuVideoDecodeAccelerator::SendEosIfNeededOrReusePicture( + uint32_t index) { + if (pending_eos_output_buffer_) { + BufferMetadata metadata; + metadata.flags = BUFFER_FLAG_EOS; + arc_client_->OnBufferDone(PORT_OUTPUT, index, metadata); + pending_eos_output_buffer_ = false; + } else { + if (buffers_pending_import_[index].is_valid()) { + std::vector<gfx::GpuMemoryBufferHandle> buffers; + buffers.push_back(gfx::GpuMemoryBufferHandle()); +#if defined(USE_OZONE) + buffers.back().native_pixmap_handle.fd = + base::FileDescriptor(buffers_pending_import_[index].release(), true); +#endif + vda_->ImportBufferForPicture(index, buffers); + } else { + vda_->ReusePictureBuffer(index); + } + } +} + +void ArcGpuVideoDecodeAccelerator::CreateInputRecord( + int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp) { + input_records_.push_front( + InputRecord(bitstream_buffer_id, buffer_index, timestamp)); + + // The same value copied from media::GpuVideoDecoder. The input record is + // needed when the input buffer or the corresponding output buffer are + // returned from VDA. However there is no guarantee how much buffers will be + // kept in the VDA. We kept the last |kMaxNumberOfInputRecords| in + // |input_records_| and drop the others. + const size_t kMaxNumberOfInputRecords = 128; + if (input_records_.size() > kMaxNumberOfInputRecords) + input_records_.pop_back(); +} + +ArcGpuVideoDecodeAccelerator::InputRecord* +ArcGpuVideoDecodeAccelerator::FindInputRecord(int32_t bitstream_buffer_id) { + for (auto& record : input_records_) { + if (record.bitstream_buffer_id == bitstream_buffer_id) + return &record; + } + return nullptr; +} + +bool ArcGpuVideoDecodeAccelerator::ValidatePortAndIndex(PortType port, + uint32_t index) { + switch (port) { + case PORT_INPUT: + if (index >= input_buffer_info_.size()) { + DLOG(ERROR) << "Invalid index: " << index; + return false; + } + return true; + case PORT_OUTPUT: + if (index >= buffers_pending_import_.size()) { + DLOG(ERROR) << "Invalid index: " << index; + return false; + } + return true; + default: + DLOG(ERROR) << "Invalid port: " << port; + return false; + } +} + +} // namespace arc +} // namespace chromeos
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.h b/chrome/gpu/arc_gpu_video_decode_accelerator.h new file mode 100644 index 0000000..1959a1ebaf --- /dev/null +++ b/chrome/gpu/arc_gpu_video_decode_accelerator.h
@@ -0,0 +1,152 @@ +// Copyright 2016 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_GPU_ARC_GPU_VIDEO_DECODE_ACCELERATOR_H_ +#define CHROME_GPU_ARC_GPU_VIDEO_DECODE_ACCELERATOR_H_ + +#include <list> +#include <queue> +#include <vector> + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" +#include "chrome/gpu/arc_video_accelerator.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "media/video/video_decode_accelerator.h" + +namespace chromeos { +namespace arc { + +// This class is executed in the GPU process. It takes decoding requests from +// ARC via IPC channels and translates and sends those requests to an +// implementation of media::VideoDecodeAccelerator. It also returns the decoded +// frames back to the ARC side. +class ArcGpuVideoDecodeAccelerator + : public ArcVideoAccelerator, + public media::VideoDecodeAccelerator::Client, + public base::SupportsWeakPtr<ArcGpuVideoDecodeAccelerator> { + public: + ArcGpuVideoDecodeAccelerator(); + ~ArcGpuVideoDecodeAccelerator() override; + + // Implementation of the ArcVideoAccelerator interface. + bool Initialize(const Config& config, + ArcVideoAccelerator::Client* client) override; + void SetNumberOfOutputBuffers(size_t number) override; + void BindSharedMemory(PortType port, + uint32_t index, + base::ScopedFD ashmem_fd, + off_t offset, + size_t length) override; + void BindDmabuf(PortType port, + uint32_t index, + base::ScopedFD dmabuf_fd) override; + void UseBuffer(PortType port, + uint32_t index, + const BufferMetadata& metadata) override; + void Reset() override; + + // Implementation of the VideoDecodeAccelerator::Client interface. + void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, + const gfx::Size& dimensions, + uint32_t texture_target) override; + void DismissPictureBuffer(int32_t picture_buffer) override; + void PictureReady(const media::Picture& picture) override; + void NotifyEndOfBitstreamBuffer(int32_t bitstream_buffer_id) override; + void NotifyFlushDone() override; + void NotifyResetDone() override; + void NotifyError(media::VideoDecodeAccelerator::Error error) override; + + private: + // Some information related to a bitstream buffer. The information is required + // when input or output buffers are returned back to the client. + struct InputRecord { + int32_t bitstream_buffer_id; + uint32_t buffer_index; + int64_t timestamp; + + InputRecord(int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp); + }; + + // The information about the shared memory used as an input buffer. + struct InputBufferInfo { + // The file handle to access the buffer. It is owned by this class and + // should be closed after use. + base::ScopedFD handle; + off_t offset; + size_t length; + + InputBufferInfo(); + InputBufferInfo(InputBufferInfo&& other); + ~InputBufferInfo(); + }; + + // Helper function to Send the end-of-stream output buffer if + // |pending_eos_output_buffer_| is true, or reuse the picture in ArcVDA. + void SendEosIfNeededOrReusePicture(uint32_t index); + + // Helper function to validate |port| and |index|. + bool ValidatePortAndIndex(PortType port, uint32_t index); + + // Creates an InputRecord for the given |bitstream_buffer_id|. The + // |buffer_index| is the index of the associated input buffer. The |timestamp| + // is the time the video frame should be displayed. + void CreateInputRecord(int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp); + + // Finds the InputRecord which matches to given |bitstream_buffer_id|. + // Returns |nullptr| if it cannot be found. + InputRecord* FindInputRecord(int32_t bitstream_buffer_id); + + // When true, an EOS output buffer need to be sent to |arc_client_| once an + // output buffer is available. + bool pending_eos_output_buffer_; + + scoped_ptr<media::VideoDecodeAccelerator> vda_; + + // It's safe to use the pointer here, the life cycle of the |arc_client_| + // is longer than this ArcGpuVideoDecodeAccelerator. + ArcVideoAccelerator::Client* arc_client_; + + // The next ID for the bitstream buffer, started from 0. + int32_t next_bitstream_buffer_id_; + + gfx::Size coded_size_; + + // The |picture_buffer_id|s for Pictures that were returned to us from VDA + // via PictureReady() while flushing. We keep them until NotifyFlushDone(); + // once it's called, we send one of the pending buffers from this queue (if + // not empty), marked with an EOS flag, to |arc_client_|, and return the rest + // to VDA for reuse. + std::queue<int32_t> buffers_pending_eos_; + + // A list of most recent |kMaxNumberOfInputRecord| InputRecords. + // |kMaxNumberOfInputRecord| is defined in the cc file. + std::list<InputRecord> input_records_; + + // The details of the shared memory of each input buffers. + std::vector<InputBufferInfo> input_buffer_info_; + + // To keep those output buffers which have been bound by bindDmabuf() but not + // be used yet. Will call VDA::ImportBufferForPicture() when those buffers are + // used for the first time. + std::vector<base::ScopedFD> buffers_pending_import_; + + base::ThreadChecker thread_checker_; + size_t output_buffer_size_; + + gpu::GpuPreferences gpu_preferences_; + + DISALLOW_COPY_AND_ASSIGN(ArcGpuVideoDecodeAccelerator); +}; + +} // namespace arc +} // namespace chromeos + +#endif // CHROME_GPU_ARC_GPU_VIDEO_DECODE_ACCELERATOR_H_
diff --git a/chrome/gpu/gpu_arc_video_service.cc b/chrome/gpu/gpu_arc_video_service.cc index d53076d6..0ab69c7 100644 --- a/chrome/gpu/gpu_arc_video_service.cc +++ b/chrome/gpu/gpu_arc_video_service.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/thread_task_runner_handle.h" +#include "chrome/gpu/arc_gpu_video_decode_accelerator.h" #include "chrome/gpu/arc_video_accelerator.h" #include "components/arc/common/video_accelerator.mojom.h" #include "mojo/edk/embedder/embedder.h" @@ -112,8 +113,7 @@ base::Bind(&GpuArcVideoService::AcceleratorStub::OnConnectionError, base::Unretained(this))); - // TODO(kcwu): create ArcGpuVideoDecodeAccelerator here. - // accelerator_.reset(new ArcGpuVideoDecodeAccelerator()); + accelerator_.reset(new ArcGpuVideoDecodeAccelerator()); ::arc::mojom::VideoAcceleratorServicePtr service; binding_.Bind(GetProxy(&service));
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index fe418eea..0f3906c1 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -19,7 +19,7 @@ [ "chromeos.gyp" ]) component("chromeos") { - configs += [ "//net/third_party/nss/ssl:ssl_config" ] + configs += [ "//third_party/nss:system_nss_no_ssl_config" ] public_deps = [ "//dbus", ] @@ -138,7 +138,7 @@ test("chromeos_unittests") { configs += [ "//build/config/linux:dbus", - "//net/third_party/nss/ssl:ssl_config", + "//third_party/nss:system_nss_no_ssl_config", ] deps = [ ":cryptohome_proto",
diff --git a/components/certificate_reporting/error_reporter.cc b/components/certificate_reporting/error_reporter.cc index 6cfa629..9c8bb83 100644 --- a/components/certificate_reporting/error_reporter.cc +++ b/components/certificate_reporting/error_reporter.cc
@@ -10,11 +10,7 @@ #include "base/logging.h" #include "components/certificate_reporting/encrypted_cert_logger.pb.h" - -#if defined(USE_OPENSSL) #include "crypto/aead_openssl.h" -#endif - #include "crypto/curve25519.h" #include "crypto/hkdf.h" #include "crypto/random.h" @@ -32,8 +28,6 @@ 0x31, 0x1a, 0x39, 0x5b, 0x76, 0xb1, 0x6b, 0x3d, 0x6a, 0x2b}; static const uint32_t kServerPublicKeyVersion = 1; -#if defined(USE_OPENSSL) - static const char kHkdfLabel[] = "certificate report"; bool GetHkdfSubkeySecret(size_t subkey_length, @@ -101,7 +95,6 @@ EncryptedCertLoggerRequest::AEAD_ECDH_AES_128_CTR_HMAC_SHA256); return true; } -#endif } // namespace @@ -137,7 +130,6 @@ certificate_report_sender_->Send(upload_url_, serialized_report); } else { DCHECK(IsHttpUploadUrlSupported()); -#if defined(USE_OPENSSL) EncryptedCertLoggerRequest encrypted_report; if (!EncryptSerializedReport(server_public_key_, server_public_key_version_, serialized_report, &encrypted_report)) { @@ -147,20 +139,14 @@ std::string serialized_encrypted_report; encrypted_report.SerializeToString(&serialized_encrypted_report); certificate_report_sender_->Send(upload_url_, serialized_encrypted_report); -#endif } } bool ErrorReporter::IsHttpUploadUrlSupported() { -#if defined(USE_OPENSSL) return true; -#else - return false; -#endif } // Used only by tests. -#if defined(USE_OPENSSL) bool ErrorReporter::DecryptErrorReport( const uint8_t server_private_key[32], const EncryptedCertLoggerRequest& encrypted_report, @@ -182,6 +168,5 @@ return aead.Open(encrypted_report.encrypted_report(), nonce, std::string(), decrypted_serialized_report); } -#endif } // namespace certificate_reporting
diff --git a/components/certificate_reporting/error_reporter.h b/components/certificate_reporting/error_reporter.h index f090817..67e4bd3 100644 --- a/components/certificate_reporting/error_reporter.h +++ b/components/certificate_reporting/error_reporter.h
@@ -68,13 +68,11 @@ // Whether sending reports over HTTP is supported. static bool IsHttpUploadUrlSupported(); -#if defined(USE_OPENSSL) // Used by tests. static bool DecryptErrorReport( const uint8_t server_private_key[32], const EncryptedCertLoggerRequest& encrypted_report, std::string* decrypted_serialized_report); -#endif private: scoped_ptr<net::CertificateReportSender> certificate_report_sender_;
diff --git a/components/certificate_reporting/error_reporter_unittest.cc b/components/certificate_reporting/error_reporter_unittest.cc index ac8ec38..e38a47c 100644 --- a/components/certificate_reporting/error_reporter_unittest.cc +++ b/components/certificate_reporting/error_reporter_unittest.cc
@@ -92,7 +92,6 @@ EXPECT_EQ(http_mock_report_sender->latest_report_uri(), http_url); std::string uploaded_report; -#if defined(USE_OPENSSL) EncryptedCertLoggerRequest encrypted_request; ASSERT_TRUE(encrypted_request.ParseFromString( http_mock_report_sender->latest_report())); @@ -102,15 +101,11 @@ encrypted_request.algorithm()); ASSERT_TRUE(ErrorReporter::DecryptErrorReport( server_private_key_, encrypted_request, &uploaded_report)); -#else - ADD_FAILURE() << "Only supported in OpenSSL ports"; -#endif EXPECT_EQ(kDummyReport, uploaded_report); } } -#if defined(USE_OPENSSL) // This test decrypts a "known gold" report. It's intentionally brittle // in order to catch changes in report encryption that could cause the // server to no longer be able to decrypt reports that it receives from @@ -270,7 +265,6 @@ ASSERT_TRUE(ErrorReporter::DecryptErrorReport( server_private_key_, encrypted_request, &decrypted_serialized_report)); } -#endif } // namespace
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 2039ad0..c5588b20 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -1286,6 +1286,7 @@ 'test_runner/test_runner.gyp:test_runner', 'tracing.gyp:tracing', 'webcrypto/webcrypto.gyp:webcrypto', + '../third_party/boringssl/boringssl.gyp:boringssl', '../third_party/re2/re2.gyp:re2', ], 'conditions': [ @@ -1304,24 +1305,6 @@ 'components.gyp:policy_java', ], }], - ['use_openssl==1', { - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - }, { - 'conditions': [ - ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', { - 'dependencies': [ - '../build/linux/system.gyp:ssl', - ], - }, { - 'dependencies': [ - '../third_party/nss/nss.gyp:nspr', - '../third_party/nss/nss.gyp:nss', - ], - }], - ], - }], ['safe_browsing == 2 and OS != "ios"', { 'dependencies': [ 'components.gyp:safe_browsing_db_mobile',
diff --git a/components/gcm_driver.gypi b/components/gcm_driver.gypi index 042397f..1531dd1 100644 --- a/components/gcm_driver.gypi +++ b/components/gcm_driver.gypi
@@ -226,6 +226,7 @@ '../components/components.gyp:leveldb_proto', '../crypto/crypto.gyp:crypto', '../net/net.gyp:net', + '../third_party/boringssl/boringssl.gyp:boringssl', ], 'include_dirs': [ '..', @@ -240,29 +241,11 @@ 'gcm_driver/crypto/gcm_key_store.h', 'gcm_driver/crypto/gcm_message_cryptographer.cc', 'gcm_driver/crypto/gcm_message_cryptographer.h', - 'gcm_driver/crypto/gcm_message_cryptographer_nss.cc', 'gcm_driver/crypto/gcm_message_cryptographer_openssl.cc', 'gcm_driver/crypto/p256_key_util.cc', 'gcm_driver/crypto/p256_key_util.h', - 'gcm_driver/crypto/p256_key_util_nss.cc', 'gcm_driver/crypto/p256_key_util_openssl.cc', ], - 'conditions': [ - ['use_openssl==1', { - 'sources!': [ - 'gcm_driver/crypto/gcm_message_cryptographer_nss.cc', - 'gcm_driver/crypto/p256_key_util_nss.cc', - ], - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - }, { - 'sources!': [ - 'gcm_driver/crypto/gcm_message_cryptographer_openssl.cc', - 'gcm_driver/crypto/p256_key_util_openssl.cc', - ], - }], - ], }, { # GN version: //components/gcm_driver/crypto/proto
diff --git a/components/gcm_driver/crypto/BUILD.gn b/components/gcm_driver/crypto/BUILD.gn index 778c1c8..7dd4d73 100644 --- a/components/gcm_driver/crypto/BUILD.gn +++ b/components/gcm_driver/crypto/BUILD.gn
@@ -15,11 +15,9 @@ "gcm_key_store.h", "gcm_message_cryptographer.cc", "gcm_message_cryptographer.h", - "gcm_message_cryptographer_nss.cc", "gcm_message_cryptographer_openssl.cc", "p256_key_util.cc", "p256_key_util.h", - "p256_key_util_nss.cc", "p256_key_util_openssl.cc", ] @@ -33,18 +31,6 @@ "//net", "//third_party/protobuf:protobuf_lite", ] - - if (use_openssl) { - sources -= [ - "gcm_message_cryptographer_nss.cc", - "p256_key_util_nss.cc", - ] - } else { - sources -= [ - "gcm_message_cryptographer_openssl.cc", - "p256_key_util_openssl.cc", - ] - } } # GYP version: components/gcm_driver.gypi:gcm_driver_crypto_test_support
diff --git a/components/gcm_driver/crypto/gcm_message_cryptographer_nss.cc b/components/gcm_driver/crypto/gcm_message_cryptographer_nss.cc deleted file mode 100644 index accf456..0000000 --- a/components/gcm_driver/crypto/gcm_message_cryptographer_nss.cc +++ /dev/null
@@ -1,94 +0,0 @@ -// 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 "components/gcm_driver/crypto/gcm_message_cryptographer.h" - -#include <pk11pub.h> -#include <secerr.h> -#include <stddef.h> - -#include "base/logging.h" -#include "base/numerics/safe_math.h" -#include "base/strings/string_util.h" -#include "crypto/scoped_nss_types.h" - -namespace gcm { - -bool GCMMessageCryptographer::EncryptDecryptRecordInternal( - Mode mode, - const base::StringPiece& input, - const base::StringPiece& key, - const base::StringPiece& nonce, - std::string* output) const { - DCHECK(output); - - SECItem key_item; - key_item.type = siBuffer; - key_item.data = const_cast<unsigned char*>( - reinterpret_cast<const unsigned char*>(key.data())); - key_item.len = key.size(); - - const CK_ATTRIBUTE_TYPE cka_mode = mode == ENCRYPT ? CKA_ENCRYPT - : CKA_DECRYPT; - - crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); - crypto::ScopedPK11SymKey aead_key( - PK11_ImportSymKey(slot.get(), CKM_AES_GCM, PK11_OriginUnwrap, cka_mode, - &key_item, nullptr)); - - CK_GCM_PARAMS gcm_params; - gcm_params.pIv = const_cast<unsigned char*>( - reinterpret_cast<const unsigned char*>(nonce.data())); - gcm_params.ulIvLen = nonce.size(); - - gcm_params.pAAD = nullptr; - gcm_params.ulAADLen = 0; - - gcm_params.ulTagBits = kAuthenticationTagBytes * 8; - - SECItem param; - param.type = siBuffer; - param.data = reinterpret_cast<unsigned char*>(&gcm_params); - param.len = sizeof(gcm_params); - - base::CheckedNumeric<size_t> maximum_output_length(input.size()); - if (mode == ENCRYPT) - maximum_output_length += kAuthenticationTagBytes; - - // WriteInto requires the buffer to finish with a NULL-byte. - maximum_output_length += 1; - - unsigned int output_length = 0; - unsigned char* raw_input = const_cast<unsigned char*>( - reinterpret_cast<const unsigned char*>(input.data())); - unsigned char* raw_output = reinterpret_cast<unsigned char*>( - base::WriteInto(output, maximum_output_length.ValueOrDie())); - - if (mode == ENCRYPT) { - if (PK11_Encrypt(aead_key.get(), CKM_AES_GCM, ¶m, raw_output, - &output_length, output->size(), raw_input, - input.size()) != SECSuccess) { - return false; - } - } else { - if (PK11_Decrypt(aead_key.get(), CKM_AES_GCM, ¶m, raw_output, - &output_length, output->size(), raw_input, - input.size()) != SECSuccess) { - return false; - } - } - - base::CheckedNumeric<size_t> expected_output_length(input.size()); - if (mode == ENCRYPT) - expected_output_length += kAuthenticationTagBytes; - else - expected_output_length -= kAuthenticationTagBytes; - - DCHECK_EQ(expected_output_length.ValueOrDie(), output_length); - - output->resize(output_length); - return true; -} - -} // namespace gcm
diff --git a/components/gcm_driver/crypto/p256_key_util_nss.cc b/components/gcm_driver/crypto/p256_key_util_nss.cc deleted file mode 100644 index 260efc8..0000000 --- a/components/gcm_driver/crypto/p256_key_util_nss.cc +++ /dev/null
@@ -1,102 +0,0 @@ -// 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 "components/gcm_driver/crypto/p256_key_util.h" - -#include <stddef.h> -#include <stdint.h> -#include <string.h> -#include <vector> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "crypto/ec_private_key.h" -#include "crypto/scoped_nss_types.h" - -namespace gcm { - -namespace { - -// A P-256 field element consists of 32 bytes. -const size_t kFieldBytes = 32; - -} // namespace - -bool ComputeSharedP256Secret(const base::StringPiece& private_key, - const base::StringPiece& public_key_x509, - const base::StringPiece& peer_public_key, - std::string* out_shared_secret) { - DCHECK(out_shared_secret); - - scoped_ptr<crypto::ECPrivateKey> local_key_pair( - crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - "" /* no password */, - std::vector<uint8_t>( - private_key.data(), private_key.data() + private_key.size()), - std::vector<uint8_t>( - public_key_x509.data(), - public_key_x509.data() + public_key_x509.size()))); - - if (!local_key_pair) { - DLOG(ERROR) << "Unable to create the local key pair."; - return false; - } - - SECKEYPublicKey public_key_peer; - memset(&public_key_peer, 0, sizeof(public_key_peer)); - - public_key_peer.keyType = ecKey; - // Both sides of a ECDH key exchange need to use the same EC params. - public_key_peer.u.ec.DEREncodedParams.len = - local_key_pair->public_key()->u.ec.DEREncodedParams.len; - public_key_peer.u.ec.DEREncodedParams.data = - local_key_pair->public_key()->u.ec.DEREncodedParams.data; - - public_key_peer.u.ec.publicValue.type = siBuffer; - public_key_peer.u.ec.publicValue.data = - reinterpret_cast<uint8_t*>(const_cast<char*>(peer_public_key.data())); - public_key_peer.u.ec.publicValue.len = peer_public_key.size(); - - // The NSS function performing ECDH key exchange is PK11_PubDeriveWithKDF. - // As this function is used for SSL/TLS's ECDH key exchanges it has many - // arguments, most of which are not required. Key derivation function CKD_NULL - // is used because the return value of |CalculateSharedKey| is the actual ECDH - // shared key, not any derived keys from it. - crypto::ScopedPK11SymKey premaster_secret( - PK11_PubDeriveWithKDF( - local_key_pair->key(), - &public_key_peer, - PR_FALSE /* isSender */, - nullptr /* randomA */, - nullptr /* randomB */, - CKM_ECDH1_DERIVE, - CKM_GENERIC_SECRET_KEY_GEN, - CKA_DERIVE, - 0 /* keySize */, - CKD_NULL /* kdf */, - nullptr /* sharedData */, - nullptr /* wincx */)); - - if (!premaster_secret) { - DLOG(ERROR) << "Unable to derive the ECDH shared key."; - return false; - } - - if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) { - DLOG(ERROR) << "Unable to extract the raw ECDH shared secret."; - return false; - } - - SECItem* key_data = PK11_GetKeyData(premaster_secret.get()); - if (!key_data || !key_data->data || key_data->len != kFieldBytes) { - DLOG(ERROR) << "The raw ECDH shared secret is invalid."; - return false; - } - - out_shared_secret->assign( - reinterpret_cast<char*>(key_data->data), key_data->len); - return true; -} - -} // namespace gcm
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/ntp_snippets_service_unittest.cc index 02be166..9eab18d 100644 --- a/components/ntp_snippets/ntp_snippets_service_unittest.cc +++ b/components/ntp_snippets/ntp_snippets_service_unittest.cc
@@ -13,10 +13,14 @@ #include "base/time/time.h" #include "components/ntp_snippets/ntp_snippet.h" #include "components/ntp_snippets/ntp_snippets_fetcher.h" +#include "components/ntp_snippets/ntp_snippets_scheduler.h" #include "components/prefs/testing_pref_service.h" #include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::_; + namespace ntp_snippets { namespace { @@ -100,6 +104,16 @@ } } +class MockScheduler : public NTPSnippetsScheduler { + public: + MOCK_METHOD4(Schedule, + bool(base::TimeDelta period_wifi_charging, + base::TimeDelta period_wifi, + base::TimeDelta period_fallback, + base::Time reschedule_time)); + MOCK_METHOD0(Unschedule, bool()); +}; + } // namespace class NTPSnippetsServiceTest : public testing::Test { @@ -114,24 +128,32 @@ CreateSnippetsService(); } - void CreateSnippetsService() { + virtual void CreateSnippetsService() { + CreateSnippetsServiceEnabled(true); + } + + void CreateSnippetsServiceEnabled(bool enabled) { + scheduler_.reset(new MockScheduler); scoped_refptr<base::SingleThreadTaskRunner> task_runner( base::ThreadTaskRunnerHandle::Get()); scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = new net::TestURLRequestContextGetter(task_runner.get()); service_.reset(new NTPSnippetsService( - pref_service_.get(), nullptr, task_runner, std::string("fr"), nullptr, + pref_service_.get(), nullptr, task_runner, std::string("fr"), + scheduler_.get(), make_scoped_ptr(new NTPSnippetsFetcher( task_runner, std::move(request_context_getter), true)), base::Bind(&ParseJson, true))); - service_->Init(true); + if (enabled) + EXPECT_CALL(*scheduler_, Schedule(_, _, _, _)); + else + EXPECT_CALL(*scheduler_, Unschedule()); + service_->Init(enabled); } protected: - NTPSnippetsService* service() { - return service_.get(); - } + NTPSnippetsService* service() { return service_.get(); } void LoadFromJSONString(const std::string& json) { service_->OnSnippetsDownloaded(json); @@ -145,10 +167,26 @@ base::MessageLoop message_loop_; scoped_ptr<TestingPrefServiceSimple> pref_service_; scoped_ptr<NTPSnippetsService> service_; + scoped_ptr<MockScheduler> scheduler_; DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest); }; +class NTPSnippetsServiceDisabledTest : public NTPSnippetsServiceTest { + public: + void CreateSnippetsService() override { + CreateSnippetsServiceEnabled(false); + } +}; + +TEST_F(NTPSnippetsServiceTest, Schedule) { + // CreateSnippetsServiceEnabled checks that Schedule is called. +} + +TEST_F(NTPSnippetsServiceDisabledTest, Unschedule) { + // CreateSnippetsServiceEnabled checks that Unschedule is called. +} + TEST_F(NTPSnippetsServiceTest, Loop) { std::string json_str( "{ \"recos\": [ "
diff --git a/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc b/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc index ce644d4..c912032 100644 --- a/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc +++ b/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc
@@ -264,19 +264,8 @@ } } -// TODO(crbug.com/604721): original CL never compiled this file with gyp and -// thus the test was never run on iOS and is now failing. Disabled until the -// bug is fixed to unblock conversion to gn. -#if !defined(OS_IOS) -#define MAYBE_ReconcileWhenWhenBothPrefsTypesArrivesFromSync \ - ReconcileWhenWhenBothPrefsTypesArrivesFromSync -#else -#define MAYBE_ReconcileWhenWhenBothPrefsTypesArrivesFromSync \ - DISABLED_ReconcileWhenWhenBothPrefsTypesArrivesFromSync -#endif - TEST_F(PasswordManagerSettingMigratorServiceTest, - MAYBE_ReconcileWhenWhenBothPrefsTypesArrivesFromSync) { + ReconcileWhenWhenBothPrefsTypesArrivesFromSync) { const struct { BooleanPrefState new_pref_local_value; BooleanPrefState old_pref_local_value;
diff --git a/components/quirks/quirks_manager.cc b/components/quirks/quirks_manager.cc index 4875ee4..db97631 100644 --- a/components/quirks/quirks_manager.cc +++ b/components/quirks/quirks_manager.cc
@@ -126,9 +126,9 @@ return; waiting_for_login_ = false; - if (!QuirksEnabled()) { - VLOG(1) << "Quirks Client disabled by device policy."; - return; + if (!clients_.empty() && !QuirksEnabled()) { + VLOG(2) << clients_.size() << " client(s) deleted."; + clients_.clear(); } for (const scoped_ptr<QuirksClient>& client : clients_) @@ -252,9 +252,16 @@ } bool QuirksManager::QuirksEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableQuirksClient) && - delegate_->DevicePolicyEnabled(); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableQuirksClient)) { + VLOG(2) << "Quirks Client disabled by command line flag."; + return false; + } + if (!delegate_->DevicePolicyEnabled()) { + VLOG(2) << "Quirks Client disabled by device policy."; + return false; + } + return true; } void QuirksManager::SetLastServerCheck(int64_t product_id,
diff --git a/components/quirks/switches.cc b/components/quirks/switches.cc index fd61a5d..c0a4622a 100644 --- a/components/quirks/switches.cc +++ b/components/quirks/switches.cc
@@ -7,8 +7,8 @@ namespace quirks { namespace switches { -// Enable Quirks Client for handling display calibration information. -const char kEnableQuirksClient[] = "enable-quirks-client"; +// Disable Quirks Client for handling display calibration information. +const char kDisableQuirksClient[] = "disable-quirks-client"; } // namespace switches } // namespace quirks
diff --git a/components/quirks/switches.h b/components/quirks/switches.h index e359dcf..2c14926 100644 --- a/components/quirks/switches.h +++ b/components/quirks/switches.h
@@ -12,7 +12,7 @@ // All switches in alphabetical order. The switches should be documented // alongside the definition of their values in the .cc file. -QUIRKS_EXPORT extern const char kEnableQuirksClient[]; +QUIRKS_EXPORT extern const char kDisableQuirksClient[]; } // namespace switches } // namespace quirks
diff --git a/components/test_runner/layout_test_runtime_flags.cc b/components/test_runner/layout_test_runtime_flags.cc index 7f2410c..63e3310 100644 --- a/components/test_runner/layout_test_runtime_flags.cc +++ b/components/test_runner/layout_test_runtime_flags.cc
@@ -27,6 +27,7 @@ set_policy_delegate_is_permissive(false); set_policy_delegate_should_notify_done(false); set_wait_until_done(false); + set_wait_until_external_url_load(false); set_dump_selection_rect(false); set_dump_drag_image(false); @@ -42,6 +43,21 @@ set_displaying_insecure_content_allowed(false); set_running_insecure_content_allowed(false); + set_dump_editting_callbacks(false); + set_dump_frame_load_callbacks(false); + set_dump_ping_loader_callbacks(false); + set_dump_user_gesture_in_frame_load_callbacks(false); + set_dump_resource_load_callbacks(false); + set_dump_resource_priorities(false); + set_dump_resource_response_mime_types(false); + set_dump_navigation_policy(false); + set_intercept_post_message(false); + + set_dump_title_changes(false); + set_dump_icon_changes(false); + + set_stay_on_page_after_handling_before_unload(false); + // No need to report the initial state - only the future delta is important. tracked_dictionary().ResetChangeTracking(); }
diff --git a/components/test_runner/layout_test_runtime_flags.h b/components/test_runner/layout_test_runtime_flags.h index c772ba8..0a4355b 100644 --- a/components/test_runner/layout_test_runtime_flags.h +++ b/components/test_runner/layout_test_runtime_flags.h
@@ -78,6 +78,10 @@ // If true, don't dump output until notifyDone is called. DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(wait_until_done) + // If true, ends the test when a URL is loaded externally via + // WebFrameClient::loadURLExternally(). + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(wait_until_external_url_load) + // Causes navigation actions just printout the intended navigation instead // of taking you to the page. This is used for cases like mailto, where you // don't actually want to open the mail program. @@ -111,6 +115,49 @@ DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG( dump_web_content_settings_client_callbacks) + // If true, the test_shell will write a descriptive line for each editing + // command. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_editting_callbacks) + + // If true, the test_shell will output a descriptive line for each frame + // load callback. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_frame_load_callbacks) + + // If true, the test_shell will output a descriptive line for each + // PingLoader dispatched. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_ping_loader_callbacks) + + // If true, the test_shell will output a line of the user gesture status + // text for some frame load callbacks. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG( + dump_user_gesture_in_frame_load_callbacks) + + // If true, the test_shell will output a descriptive line for each resource + // load callback. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_resource_load_callbacks) + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_resource_priorities) + + // If true, the test_shell will output the MIME type for each resource that + // was loaded. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_resource_response_mime_types) + + // If true, content_shell will dump the default navigation policy passed to + // WebFrameClient::decidePolicyForNavigation. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_navigation_policy) + + // Bound variable to set whether postMessages should be intercepted or not + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(intercept_post_message) + + // If true, output a message when the page title is changed. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_title_changes) + + // If true, the test_shell will print out the icon change notifications. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_icon_changes) + + // Desired return value of WebFrameClient::runModalBeforeUnloadDialog. + DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG( + stay_on_page_after_handling_before_unload) + #undef DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG #undef DEFINE_STRING_LAYOUT_TEST_RUNTIME_FLAG
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc index 34af6df2..5fd5a1b3 100644 --- a/components/test_runner/test_runner.cc +++ b/components/test_runner/test_runner.cc
@@ -1492,13 +1492,15 @@ bool TestRunnerBindings::InterceptPostMessage() { if (runner_) - return runner_->intercept_post_message_; + return runner_->shouldInterceptPostMessage(); return false; } void TestRunnerBindings::SetInterceptPostMessage(bool value) { - if (runner_) - runner_->intercept_post_message_ = value; + if (runner_) { + runner_->layout_test_runtime_flags_.set_intercept_post_message(value); + runner_->OnLayoutTestRuntimeFlagsChanged(); + } } void TestRunnerBindings::ForceNextWebGLContextCreationToFail() { @@ -1571,7 +1573,6 @@ close_remaining_windows_(false), work_queue_(this), web_history_item_count_(0), - intercept_post_message_(false), test_interfaces_(interfaces), delegate_(nullptr), web_view_(nullptr), @@ -1624,7 +1625,6 @@ mock_screen_orientation_client_->ResetData(); drag_image_.reset(); views_with_scheduled_animations_.clear(); - wait_until_external_url_load_ = false; WebSecurityPolicy::resetOriginAccessWhitelists(); #if defined(__linux__) || defined(ANDROID) @@ -1647,26 +1647,15 @@ ResetDeviceLight(); } - dump_editting_callbacks_ = false; - dump_icon_changes_ = false; dump_as_audio_ = false; - dump_frame_load_callbacks_ = false; - dump_ping_loader_callbacks_ = false; - dump_user_gesture_in_frame_load_callbacks_ = false; - dump_title_changes_ = false; dump_create_view_ = false; can_open_windows_ = false; - dump_resource_load_callbacks_ = false; - dump_resource_response_mime_types_ = false; dump_window_status_changes_ = false; dump_spell_check_callbacks_ = false; dump_back_forward_list_ = false; - dump_navigation_policy_ = false; test_repaint_ = false; sweep_horizontally_ = false; midi_accessor_result_ = true; - should_stay_on_page_after_handling_before_unload_ = false; - should_dump_resource_priorities_ = false; has_custom_text_output_ = false; custom_text_output_.clear(); @@ -1675,7 +1664,6 @@ platform_name_ = "chromium"; tooltip_text_ = std::string(); web_history_item_count_ = 0; - intercept_post_message_ = false; SetUseMockTheme(true); @@ -1765,7 +1753,7 @@ } bool TestRunner::shouldDumpEditingCallbacks() const { - return dump_editting_callbacks_; + return layout_test_runtime_flags_.dump_editting_callbacks(); } void TestRunner::setShouldDumpAsText(bool value) { @@ -1797,7 +1785,7 @@ } bool TestRunner::shouldStayOnPageAfterHandlingBeforeUnload() const { - return should_stay_on_page_after_handling_before_unload_; + return layout_test_runtime_flags_.stay_on_page_after_handling_before_unload(); } @@ -1867,15 +1855,18 @@ } bool TestRunner::shouldDumpFrameLoadCallbacks() const { - return test_is_running_ && dump_frame_load_callbacks_; + return test_is_running_ && + layout_test_runtime_flags_.dump_frame_load_callbacks(); } void TestRunner::setShouldDumpFrameLoadCallbacks(bool value) { - dump_frame_load_callbacks_ = value; + layout_test_runtime_flags_.set_dump_frame_load_callbacks(value); + OnLayoutTestRuntimeFlagsChanged(); } bool TestRunner::shouldDumpPingLoaderCallbacks() const { - return test_is_running_ && dump_ping_loader_callbacks_; + return test_is_running_ && + layout_test_runtime_flags_.dump_ping_loader_callbacks(); } void TestRunner::setShouldEnableViewSource(bool value) { @@ -1883,15 +1874,16 @@ } bool TestRunner::shouldDumpUserGestureInFrameLoadCallbacks() const { - return test_is_running_ && dump_user_gesture_in_frame_load_callbacks_; + return test_is_running_ && + layout_test_runtime_flags_.dump_user_gesture_in_frame_load_callbacks(); } bool TestRunner::shouldDumpTitleChanges() const { - return dump_title_changes_; + return layout_test_runtime_flags_.dump_title_changes(); } bool TestRunner::shouldDumpIconChanges() const { - return dump_icon_changes_; + return layout_test_runtime_flags_.dump_icon_changes(); } bool TestRunner::shouldDumpCreateView() const { @@ -1903,11 +1895,13 @@ } bool TestRunner::shouldDumpResourceLoadCallbacks() const { - return test_is_running_ && dump_resource_load_callbacks_; + return test_is_running_ && + layout_test_runtime_flags_.dump_resource_load_callbacks(); } bool TestRunner::shouldDumpResourceResponseMIMETypes() const { - return test_is_running_ && dump_resource_response_mime_types_; + return test_is_running_ && + layout_test_runtime_flags_.dump_resource_response_mime_types(); } WebContentSettingsClient* TestRunner::GetWebContentSettings() const { @@ -1936,7 +1930,7 @@ } bool TestRunner::shouldWaitUntilExternalURLLoad() const { - return wait_until_external_url_load_; + return layout_test_runtime_flags_.wait_until_external_url_load(); } const std::set<std::string>* TestRunner::httpHeadersToClear() const { @@ -1980,11 +1974,11 @@ } bool TestRunner::shouldInterceptPostMessage() const { - return intercept_post_message_; + return layout_test_runtime_flags_.intercept_post_message(); } bool TestRunner::shouldDumpResourcePriorities() const { - return should_dump_resource_priorities_; + return layout_test_runtime_flags_.dump_resource_priorities(); } bool TestRunner::RequestPointerLock() { @@ -2027,7 +2021,7 @@ } bool TestRunner::shouldDumpNavigationPolicy() const { - return dump_navigation_policy_; + return layout_test_runtime_flags_.dump_navigation_policy(); } bool TestRunner::midiAccessorResult() { @@ -2655,7 +2649,8 @@ } void TestRunner::DumpEditingCallbacks() { - dump_editting_callbacks_ = true; + layout_test_runtime_flags_.set_dump_editting_callbacks(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpAsMarkup() { @@ -2692,7 +2687,8 @@ } void TestRunner::DumpIconChanges() { - dump_icon_changes_ = true; + layout_test_runtime_flags_.set_dump_icon_changes(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::SetAudioData(const gin::ArrayBufferView& view) { @@ -2703,19 +2699,24 @@ } void TestRunner::DumpFrameLoadCallbacks() { - dump_frame_load_callbacks_ = true; + layout_test_runtime_flags_.set_dump_frame_load_callbacks(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpPingLoaderCallbacks() { - dump_ping_loader_callbacks_ = true; + layout_test_runtime_flags_.set_dump_ping_loader_callbacks(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpUserGestureInFrameLoadCallbacks() { - dump_user_gesture_in_frame_load_callbacks_ = true; + layout_test_runtime_flags_.set_dump_user_gesture_in_frame_load_callbacks( + true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpTitleChanges() { - dump_title_changes_ = true; + layout_test_runtime_flags_.set_dump_title_changes(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpCreateView() { @@ -2727,11 +2728,13 @@ } void TestRunner::DumpResourceLoadCallbacks() { - dump_resource_load_callbacks_ = true; + layout_test_runtime_flags_.set_dump_resource_load_callbacks(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpResourceResponseMIMETypes() { - dump_resource_response_mime_types_ = true; + layout_test_runtime_flags_.set_dump_resource_response_mime_types(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::SetImagesAllowed(bool allowed) { @@ -2803,7 +2806,9 @@ } void TestRunner::SetShouldStayOnPageAfterHandlingBeforeUnload(bool value) { - should_stay_on_page_after_handling_before_unload_ = value; + layout_test_runtime_flags_.set_stay_on_page_after_handling_before_unload( + value); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::SetWillSendRequestClearHeader(const std::string& header) { @@ -2812,7 +2817,8 @@ } void TestRunner::DumpResourceRequestPriorities() { - should_dump_resource_priorities_ = true; + layout_test_runtime_flags_.set_dump_resource_priorities(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::SetUseMockTheme(bool use) { @@ -2826,7 +2832,8 @@ } void TestRunner::WaitUntilExternalURLLoad() { - wait_until_external_url_load_ = true; + layout_test_runtime_flags_.set_wait_until_external_url_load(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpDragImage() { @@ -2836,7 +2843,8 @@ } void TestRunner::DumpNavigationPolicy() { - dump_navigation_policy_ = true; + layout_test_runtime_flags_.set_dump_navigation_policy(true); + OnLayoutTestRuntimeFlagsChanged(); } void TestRunner::DumpPageImportanceSignals() {
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h index 2ab35da..8ea7370 100644 --- a/components/test_runner/test_runner.h +++ b/components/test_runner/test_runner.h
@@ -686,10 +686,6 @@ // setCloseRemainingWindowsWhenComplete(). bool close_remaining_windows_; - // If true, ends the test when a URL is loaded externally via - // WebFrameClient::loadURLExternally(). - bool wait_until_external_url_load_; - WorkQueue work_queue_; // Bound variable to return the name of this platform (chromium). @@ -701,37 +697,12 @@ // Bound variable counting the number of top URLs visited. int web_history_item_count_; - // Bound variable to set whether postMessages should be intercepted or not - bool intercept_post_message_; - - // If true, the test_shell will write a descriptive line for each editing - // command. - bool dump_editting_callbacks_; - // Flags controlling what content gets dumped as a layout text result. LayoutTestRuntimeFlags layout_test_runtime_flags_; - // If true, the test_shell will print out the icon change notifications. - bool dump_icon_changes_; - // If true, the test_shell will output a base64 encoded WAVE file. bool dump_as_audio_; - // If true, the test_shell will output a descriptive line for each frame - // load callback. - bool dump_frame_load_callbacks_; - - // If true, the test_shell will output a descriptive line for each - // PingLoader dispatched. - bool dump_ping_loader_callbacks_; - - // If true, the test_shell will output a line of the user gesture status - // text for some frame load callbacks. - bool dump_user_gesture_in_frame_load_callbacks_; - - // If true, output a message when the page title is changed. - bool dump_title_changes_; - // If true, output a descriptive line each time WebViewClient::createView // is invoked. bool dump_create_view_; @@ -741,14 +712,6 @@ // setCanOpenWindows(). bool can_open_windows_; - // If true, the test_shell will output a descriptive line for each resource - // load callback. - bool dump_resource_load_callbacks_; - - // If true, the test_shell will output the MIME type for each resource that - // was loaded. - bool dump_resource_response_mime_types_; - // If true, the test_shell will dump all changes to window.status. bool dump_window_status_changes_; @@ -760,10 +723,6 @@ // well. bool dump_back_forward_list_; - // If true, content_shell will dump the default navigation policy passed to - // WebFrameClient::decidePolicyForNavigation. - bool dump_navigation_policy_; - // If true, pixel dump will be produced as a series of 1px-tall, view-wide // individual paints over the height of the view. bool test_repaint_; @@ -775,10 +734,6 @@ // If false, MockWebMIDIAccessor fails on startSession() for testing. bool midi_accessor_result_; - bool should_stay_on_page_after_handling_before_unload_; - - bool should_dump_resource_priorities_; - bool has_custom_text_output_; std::string custom_text_output_;
diff --git a/components/variations/variations_seed_store_unittest.cc b/components/variations/variations_seed_store_unittest.cc index 577e3f8c..c687932 100644 --- a/components/variations/variations_seed_store_unittest.cc +++ b/components/variations/variations_seed_store_unittest.cc
@@ -329,15 +329,10 @@ seed_store.VerifySeedSignature(seed_data, seed_data)); // Using a different signature (e.g. the base64 seed data) should fail. -#if defined(USE_OPENSSL) // OpenSSL doesn't distinguish signature decode failure from the // signature not matching. EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED, seed_store.VerifySeedSignature(seed_data, base64_seed_data)); -#else - EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE, - seed_store.VerifySeedSignature(seed_data, base64_seed_data)); -#endif // Using a different seed should not match the signature. seed_data[0] = 'x';
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index d04fac6b..d36ad98 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -176,7 +176,7 @@ #include "ui/gfx/x/x11_types.h" // nogncheck #endif -#if defined(USE_NSS_CERTS) || !defined(USE_OPENSSL) +#if defined(USE_NSS_CERTS) #include "crypto/nss_util.h" #endif @@ -495,7 +495,7 @@ net::EnsureWinsockInit(); #endif -#if defined(USE_NSS_CERTS) || !defined(USE_OPENSSL) +#if defined(USE_NSS_CERTS) // We want to be sure to init NSPR on the main thread. crypto::EnsureNSPRInit(); #endif
diff --git a/content/browser/media/webrtc/webrtc_browsertest.cc b/content/browser/media/webrtc/webrtc_browsertest.cc index 7dd174f..9036deea 100644 --- a/content/browser/media/webrtc/webrtc_browsertest.cc +++ b/content/browser/media/webrtc/webrtc_browsertest.cc
@@ -96,9 +96,9 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CanSetupVideoCallWith4To3AspectRatio) { const std::string javascript = - "callAndExpectResolution({video: {mandatory: { minWidth: 960," - "maxWidth: 960, minAspectRatio: 1.333, maxAspectRatio: 1.333}}}, 960," - " 720);"; + "callAndExpectResolution({video: {mandatory: { minWidth: 320," + "maxWidth: 320, minAspectRatio: 1.333, maxAspectRatio: 1.333}}}, 320," + " 240);"; MakeTypicalPeerConnectionCall(javascript); }
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc index 38405d8..2c7774bd 100644 --- a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc +++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -83,6 +83,7 @@ // If event wasn't consumed then generate a gesture scroll for it. if (send_gestures_ && ack_result != INPUT_EVENT_ACK_STATE_CONSUMED && event_sent_for_gesture_ack_->event.canScroll && + event_sent_for_gesture_ack_->event.resendingPluginId == -1 && (scrolling_device_ == blink::WebGestureDeviceUninitialized || scrolling_device_ == blink::WebGestureDeviceTouchpad)) { WebGestureEvent scroll_update;
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 1b899725..4ca26b60 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -614,8 +614,12 @@ void ServiceWorkerVersion::Doom() { DCHECK(!HasControllee()); SetStatus(REDUNDANT); - if (running_status() == STARTING || running_status() == RUNNING) - embedded_worker_->Stop(); + if (running_status() == STARTING || running_status() == RUNNING) { + if (embedded_worker()->devtools_attached()) + stop_when_devtools_detached_ = true; + else + embedded_worker_->Stop(); + } if (!context_) return; std::vector<ServiceWorkerDatabase::ResourceRecord> resources; @@ -625,6 +629,12 @@ void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { embedded_worker()->set_devtools_attached(attached); + if (stop_when_devtools_detached_ && !attached) { + DCHECK_EQ(REDUNDANT, status()); + if (running_status() == STARTING || running_status() == RUNNING) + embedded_worker_->Stop(); + return; + } if (attached) { // TODO(falken): Canceling the timeouts when debugging could cause // heisenbugs; we should instead run them as normal show an educational
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 214cd58..af006d8 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -669,6 +669,8 @@ std::unique_ptr<Metrics> metrics_; const bool should_exclude_from_uma_ = false; + bool stop_when_devtools_detached_ = false; + base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion);
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index ba2787d..44eaf6d9 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -198,6 +198,11 @@ WebRuntimeFeatures::enableMediaDocumentDownloadButton( base::FeatureList::IsEnabled(features::kMediaDocumentDownloadButton)); + if (base::FeatureList::IsEnabled(features::kPointerEvents)) { + WebRuntimeFeatures::enableFeatureFromString( + std::string("PointerEvent"), true); + } + // Enable explicitly enabled features, and then disable explicitly disabled // ones. if (command_line.HasSwitch(switches::kEnableBlinkFeatures)) {
diff --git a/content/content_shell.gypi b/content/content_shell.gypi index cb15a5f..7d024c3 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi
@@ -269,6 +269,7 @@ ['use_x11 == 1', { 'dependencies': [ '../ui/events/devices/events_devices.gyp:events_devices', + '../ui/events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', ], }],
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index d904a830..e999affe 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -58,6 +58,10 @@ "OptimizeForSmallResource", base::FEATURE_DISABLED_BY_DEFAULT}; +// Partial support for pointer event feature. +const base::Feature kPointerEvents{"PointerEvent", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Throttle Blink's rendering pipeline based on frame visibility. const base::Feature kRenderingPipelineThrottling{ "RenderingPipelineThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 14205702..88f9d378 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -25,6 +25,7 @@ CONTENT_EXPORT extern const base::Feature kMediaDocumentDownloadButton; CONTENT_EXPORT extern const base::Feature kNonValidatingReloadOnRefreshContent; CONTENT_EXPORT extern const base::Feature kOptimizeIPCForSmallResource; +CONTENT_EXPORT extern const base::Feature kPointerEvents; CONTENT_EXPORT extern const base::Feature kRenderingPipelineThrottling; CONTENT_EXPORT extern const base::Feature kScrollAnchoring; CONTENT_EXPORT extern const base::Feature kStaleWhileRevalidate;
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc index ae67c980..2a2891c 100644 --- a/content/renderer/media/rtc_video_encoder.cc +++ b/content/renderer/media/rtc_video_encoder.cc
@@ -15,6 +15,7 @@ #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" #include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/thread_task_runner_handle.h" #include "media/base/bind_to_current_loop.h" @@ -91,20 +92,17 @@ // This private class of RTCVideoEncoder does the actual work of communicating // with a media::VideoEncodeAccelerator for handling video encoding. It can // be created on any thread, but should subsequently be posted to (and Destroy() -// called on) a single thread. Callbacks to RTCVideoEncoder are posted to the -// thread on which the instance was constructed. +// called on) a single thread. // // This class separates state related to the thread that RTCVideoEncoder -// operates on (presently the libjingle worker thread) from the thread that -// |gpu_factories_| provides for accelerator operations (presently the media -// thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while -// RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA. +// operates on from the thread that |gpu_factories_| provides for accelerator +// operations (presently the media thread). class RTCVideoEncoder::Impl : public media::VideoEncodeAccelerator::Client, public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> { public: - Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder, - media::GpuVideoAcceleratorFactories* gpu_factories); + Impl(media::GpuVideoAcceleratorFactories* gpu_factories, + webrtc::VideoCodecType video_codec_type); // Create the VEA and call Initialize() on it. Called once per instantiation, // and then the instance is bound forevermore to whichever thread made the @@ -132,9 +130,18 @@ // Request encoding parameter change for the underlying encoder. void RequestEncodingParametersChange(uint32_t bitrate, uint32_t framerate); + void RegisterEncodeCompleteCallback(base::WaitableEvent* async_waiter, + int32_t* async_retval, + webrtc::EncodedImageCallback* callback); + // Destroy this Impl's encoder. The destructor is not explicitly called, as // Impl is a base::RefCountedThreadSafe. - void Destroy(); + void Destroy(base::WaitableEvent* async_waiter); + + // Return the status of Impl. One of WEBRTC_VIDEO_CODEC_XXX value. + int32_t GetStatus() const; + + webrtc::VideoCodecType video_codec_type() { return video_codec_type_; } // media::VideoEncodeAccelerator::Client implementation. void RequireBitstreamBuffers(unsigned int input_count, @@ -180,15 +187,17 @@ // requirements. bool RequiresSizeChange(const scoped_refptr<media::VideoFrame>& frame) const; + // Return an encoded output buffer to WebRTC. + void ReturnEncodedImage(const webrtc::EncodedImage& image, + int32_t bitstream_buffer_id, + uint16_t picture_id); + + void SetStatus(int32_t status); + + // This is attached to |gpu_task_runner_|, not the thread class is constructed + // on. base::ThreadChecker thread_checker_; - // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client - // notifications. - const base::WeakPtr<RTCVideoEncoder> weak_encoder_; - - // The message loop on which to post callbacks to |weak_encoder_|. - const scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_; - // Factory for creating VEAs, shared memory buffers, etc. media::GpuVideoAcceleratorFactories* gpu_factories_; @@ -228,19 +237,36 @@ // 15 bits running index of the VP8 frames. See VP8 RTP spec for details. uint16_t picture_id_; + // webrtc::VideoEncoder encode complete callback. + webrtc::EncodedImageCallback* encoded_image_callback_; + + // The video codec type, as reported to WebRTC. + const webrtc::VideoCodecType video_codec_type_; + + // Protect |status_|. |status_| is read or written on |gpu_task_runner_| in + // Impl. It can be read in RTCVideoEncoder on other threads. + mutable base::Lock status_lock_; + + // We cannot immediately return error conditions to the WebRTC user of this + // class, as there is no error callback in the webrtc::VideoEncoder interface. + // Instead, we cache an error status here and return it the next time an + // interface entry point is called. This is protected by |status_lock_|. + int32_t status_; + DISALLOW_COPY_AND_ASSIGN(Impl); }; -RTCVideoEncoder::Impl::Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder, - media::GpuVideoAcceleratorFactories* gpu_factories) - : weak_encoder_(weak_encoder), - encoder_task_runner_(base::ThreadTaskRunnerHandle::Get()), - gpu_factories_(gpu_factories), +RTCVideoEncoder::Impl::Impl(media::GpuVideoAcceleratorFactories* gpu_factories, + webrtc::VideoCodecType video_codec_type) + : gpu_factories_(gpu_factories), async_waiter_(NULL), async_retval_(NULL), input_next_frame_(NULL), input_next_frame_keyframe_(false), - output_buffers_free_count_(0) { + output_buffers_free_count_(0), + encoded_image_callback_(nullptr), + video_codec_type_(video_codec_type), + status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) { thread_checker_.DetachFromThread(); // Picture ID should start on a random number. picture_id_ = static_cast<uint16_t>(base::RandInt(0, 0x7FFF)); @@ -255,6 +281,7 @@ DVLOG(3) << "Impl::CreateAndInitializeVEA()"; DCHECK(thread_checker_.CalledOnValidThread()); + SetStatus(WEBRTC_VIDEO_CODEC_UNINITIALIZED); RegisterAsyncWaiter(async_waiter, async_retval); // Check for overflow converting bitrate (kilobits/sec) to bits/sec. @@ -274,6 +301,8 @@ media::VideoEncodeAccelerator::kInvalidArgumentError); return; } + // RequireBitstreamBuffers or NotifyError will be called and the waiter will + // be signaled. } void RTCVideoEncoder::Impl::Enqueue(const webrtc::VideoFrame* input_frame, @@ -285,6 +314,12 @@ DCHECK(!input_next_frame_); RegisterAsyncWaiter(async_waiter, async_retval); + int32_t retval = GetStatus(); + if (retval != WEBRTC_VIDEO_CODEC_OK) { + SignalAsyncWaiter(retval); + return; + } + // If there are no free input and output buffers, drop the frame to avoid a // deadlock. If there is a free input buffer, EncodeOneFrame will run and // unblock Encode(). If there are no free input buffers but there is a free @@ -344,10 +379,24 @@ video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate); } -void RTCVideoEncoder::Impl::Destroy() { +void RTCVideoEncoder::Impl::Destroy(base::WaitableEvent* async_waiter) { DVLOG(3) << "Impl::Destroy()"; DCHECK(thread_checker_.CalledOnValidThread()); - video_encoder_.reset(); + if (video_encoder_) { + video_encoder_.reset(); + SetStatus(WEBRTC_VIDEO_CODEC_UNINITIALIZED); + } + async_waiter->Signal(); +} + +int32_t RTCVideoEncoder::Impl::GetStatus() const { + base::AutoLock lock(status_lock_); + return status_; +} + +void RTCVideoEncoder::Impl::SetStatus(int32_t status) { + base::AutoLock lock(status_lock_); + status_ = status; } void RTCVideoEncoder::Impl::RequireBitstreamBuffers( @@ -394,6 +443,8 @@ i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size())); output_buffers_free_count_++; } + DCHECK_EQ(GetStatus(), WEBRTC_VIDEO_CODEC_UNINITIALIZED); + SetStatus(WEBRTC_VIDEO_CODEC_OK); SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); } @@ -429,21 +480,18 @@ const uint32_t rtp_timestamp = static_cast<uint32_t>(capture_time_us * 90 / 1000); - std::unique_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage( + webrtc::EncodedImage image( reinterpret_cast<uint8_t*>(output_buffer->memory()), payload_size, - output_buffer->mapped_size())); - image->_encodedWidth = input_visible_size_.width(); - image->_encodedHeight = input_visible_size_.height(); - image->_timeStamp = rtp_timestamp; - image->capture_time_ms_ = capture_time_ms; - image->_frameType = + output_buffer->mapped_size()); + image._encodedWidth = input_visible_size_.width(); + image._encodedHeight = input_visible_size_.height(); + image._timeStamp = rtp_timestamp; + image.capture_time_ms_ = capture_time_ms; + image._frameType = (key_frame ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta); - image->_completeFrame = true; + image._completeFrame = true; - encoder_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RTCVideoEncoder::ReturnEncodedImage, weak_encoder_, - base::Passed(&image), bitstream_buffer_id, picture_id_)); + ReturnEncodedImage(image, bitstream_buffer_id, picture_id_); // Picture ID must wrap after reaching the maximum. picture_id_ = (picture_id_ + 1) & 0x7FFF; } @@ -462,13 +510,9 @@ video_encoder_.reset(); - if (async_waiter_) { + SetStatus(retval); + if (async_waiter_) SignalAsyncWaiter(retval); - } else { - encoder_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval)); - } } RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); } @@ -599,23 +643,87 @@ frame->visible_rect() != gfx::Rect(input_visible_size_)); } +void RTCVideoEncoder::Impl::RegisterEncodeCompleteCallback( + base::WaitableEvent* async_waiter, + int32_t* async_retval, + webrtc::EncodedImageCallback* callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(3) << "RegisterEncodeCompleteCallback()"; + RegisterAsyncWaiter(async_waiter, async_retval); + int32_t retval = GetStatus(); + if (retval == WEBRTC_VIDEO_CODEC_OK) + encoded_image_callback_ = callback; + SignalAsyncWaiter(retval); +} + +void RTCVideoEncoder::Impl::ReturnEncodedImage( + const webrtc::EncodedImage& image, + int32_t bitstream_buffer_id, + uint16_t picture_id) { + DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(3) << "ReturnEncodedImage(): " + << "bitstream_buffer_id=" << bitstream_buffer_id + << ", picture_id=" << picture_id; + + if (!encoded_image_callback_) + return; + + webrtc::RTPFragmentationHeader header; + memset(&header, 0, sizeof(header)); + switch (video_codec_type_) { + case webrtc::kVideoCodecVP8: + // Generate a header describing a single fragment. + header.VerifyAndAllocateFragmentationHeader(1); + header.fragmentationOffset[0] = 0; + header.fragmentationLength[0] = image._length; + header.fragmentationPlType[0] = 0; + header.fragmentationTimeDiff[0] = 0; + break; + case webrtc::kVideoCodecH264: + if (!GetRTPFragmentationHeaderH264(&header, image._buffer, + image._length)) { + DLOG(ERROR) << "Failed to get RTP fragmentation header for H264"; + NotifyError( + (media::VideoEncodeAccelerator::Error)WEBRTC_VIDEO_CODEC_ERROR); + return; + } + break; + default: + NOTREACHED() << "Invalid video codec type"; + return; + } + + webrtc::CodecSpecificInfo info; + memset(&info, 0, sizeof(info)); + info.codecType = video_codec_type_; + if (video_codec_type_ == webrtc::kVideoCodecVP8) { + info.codecSpecific.VP8.pictureId = picture_id; + info.codecSpecific.VP8.tl0PicIdx = -1; + info.codecSpecific.VP8.keyIdx = -1; + } + + const int32_t retval = + encoded_image_callback_->Encoded(image, &info, &header); + if (retval < 0) { + DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned " + << retval; + } + + UseOutputBitstreamBufferId(bitstream_buffer_id); +} + RTCVideoEncoder::RTCVideoEncoder( webrtc::VideoCodecType type, media::GpuVideoAcceleratorFactories* gpu_factories) - : video_codec_type_(type), - gpu_factories_(gpu_factories), + : gpu_factories_(gpu_factories), gpu_task_runner_(gpu_factories->GetTaskRunner()), - encoded_image_callback_(NULL), - impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED), - weak_factory_(this) { + impl_(new Impl(gpu_factories_, type)) { DVLOG(1) << "RTCVideoEncoder(): codec type=" << type; } RTCVideoEncoder::~RTCVideoEncoder() { DVLOG(3) << "~RTCVideoEncoder"; - DCHECK(thread_checker_.CalledOnValidThread()); Release(); - DCHECK(!impl_.get()); } int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, @@ -625,14 +733,10 @@ << ", width=" << codec_settings->width << ", height=" << codec_settings->height << ", startBitrate=" << codec_settings->startBitrate; - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!impl_.get()); - const media::VideoCodecProfile profile = - WebRTCVideoCodecToVideoCodecProfile(video_codec_type_, codec_settings); + const media::VideoCodecProfile profile = WebRTCVideoCodecToVideoCodecProfile( + impl_->video_codec_type(), codec_settings); - weak_factory_.InvalidateWeakPtrs(); - impl_ = new Impl(weak_factory_.GetWeakPtr(), gpu_factories_); base::WaitableEvent initialization_waiter(true, false); int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; gpu_task_runner_->PostTask( @@ -656,10 +760,6 @@ const webrtc::CodecSpecificInfo* codec_specific_info, const std::vector<webrtc::FrameType>* frame_types) { DVLOG(3) << "Encode()"; - if (!impl_.get()) { - DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_; - return impl_status_; - } const bool want_key_frame = frame_types && frame_types->size() && frame_types->front() == webrtc::kVideoFrameKey; @@ -683,27 +783,24 @@ int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback( webrtc::EncodedImageCallback* callback) { DVLOG(3) << "RegisterEncodeCompleteCallback()"; - DCHECK(thread_checker_.CalledOnValidThread()); - if (!impl_.get()) { - DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_; - return impl_status_; - } - - encoded_image_callback_ = callback; - return WEBRTC_VIDEO_CODEC_OK; + base::WaitableEvent register_waiter(true, false); + int32_t register_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; + gpu_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RTCVideoEncoder::Impl::RegisterEncodeCompleteCallback, impl_, + ®ister_waiter, ®ister_retval, callback)); + register_waiter.Wait(); + return register_retval; } int32_t RTCVideoEncoder::Release() { DVLOG(3) << "Release()"; - DCHECK(thread_checker_.CalledOnValidThread()); - if (impl_.get()) { - gpu_task_runner_->PostTask(FROM_HERE, - base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); - impl_ = NULL; - weak_factory_.InvalidateWeakPtrs(); - impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } + base::WaitableEvent release_waiter(true, false); + gpu_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_, &release_waiter)); + release_waiter.Wait(); return WEBRTC_VIDEO_CODEC_OK; } @@ -718,9 +815,10 @@ int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) { DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate << ", frame_rate=" << frame_rate; - if (!impl_.get()) { - DVLOG(3) << "SetRates(): returning " << impl_status_; - return impl_status_; + const int32_t retval = impl_->GetStatus(); + if (retval != WEBRTC_VIDEO_CODEC_OK) { + DVLOG(3) << "SetRates(): returning " << retval; + return retval; } gpu_task_runner_->PostTask( @@ -732,76 +830,6 @@ return WEBRTC_VIDEO_CODEC_OK; } -void RTCVideoEncoder::ReturnEncodedImage( - std::unique_ptr<webrtc::EncodedImage> image, - int32_t bitstream_buffer_id, - uint16_t picture_id) { - DCHECK(thread_checker_.CalledOnValidThread()); - DVLOG(3) << "ReturnEncodedImage(): " - << "bitstream_buffer_id=" << bitstream_buffer_id - << ", picture_id=" << picture_id; - - if (!encoded_image_callback_) - return; - - webrtc::RTPFragmentationHeader header; - memset(&header, 0, sizeof(header)); - switch (video_codec_type_) { - case webrtc::kVideoCodecVP8: - // Generate a header describing a single fragment. - header.VerifyAndAllocateFragmentationHeader(1); - header.fragmentationOffset[0] = 0; - header.fragmentationLength[0] = image->_length; - header.fragmentationPlType[0] = 0; - header.fragmentationTimeDiff[0] = 0; - break; - case webrtc::kVideoCodecH264: - if (!GetRTPFragmentationHeaderH264( - &header, image->_buffer, image->_length)) { - DLOG(ERROR) << "Failed to get RTP fragmentation header for H264"; - NotifyError(WEBRTC_VIDEO_CODEC_ERROR); - return; - } - break; - default: - NOTREACHED() << "Invalid video codec type"; - return; - } - - webrtc::CodecSpecificInfo info; - memset(&info, 0, sizeof(info)); - info.codecType = video_codec_type_; - if (video_codec_type_ == webrtc::kVideoCodecVP8) { - info.codecSpecific.VP8.pictureId = picture_id; - info.codecSpecific.VP8.tl0PicIdx = -1; - info.codecSpecific.VP8.keyIdx = -1; - } - - int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header); - if (retval < 0) { - DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned " - << retval; - } - - // The call through webrtc::EncodedImageCallback is synchronous, so we can - // immediately recycle the output buffer back to the Impl. - gpu_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId, - impl_, - bitstream_buffer_id)); -} - -void RTCVideoEncoder::NotifyError(int32_t error) { - DCHECK(thread_checker_.CalledOnValidThread()); - DVLOG(1) << "NotifyError(): error=" << error; - - impl_status_ = error; - gpu_task_runner_->PostTask(FROM_HERE, - base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); - impl_ = NULL; -} - void RTCVideoEncoder::RecordInitEncodeUMA( int32_t init_retval, media::VideoCodecProfile profile) { UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess",
diff --git a/content/renderer/media/rtc_video_encoder.h b/content/renderer/media/rtc_video_encoder.h index d0cd43a..d8c5413e 100644 --- a/content/renderer/media/rtc_video_encoder.h +++ b/content/renderer/media/rtc_video_encoder.h
@@ -32,12 +32,8 @@ // trampolined to a private RTCVideoEncoder::Impl instance. The Impl class runs // on the worker thread queried from the |gpu_factories_|, which is presently // the media thread. RTCVideoEncoder is sychronized by webrtc::VideoSender. -// webrtc::VideoEncoder methods do not run concurrently. RTCVideoEncoder is run -// and destroyed on the thread it is constructed on, which is presently the -// libjingle worker thread. Encode is run on ViECaptureThread. SetRates and -// SetChannelParameters are run on ProcessThread or the libjingle worker thread. -// Callbacks from the Impl due to its VEA::Client notifications are posted back -// to RTCVideoEncoder on the libjingle worker thread. +// webrtc::VideoEncoder methods do not run concurrently. RtcVideoEncoder needs +// to synchronize RegisterEncodeCompleteCallback and encode complete callback. class CONTENT_EXPORT RTCVideoEncoder : NON_EXPORTED_BASE(public webrtc::VideoEncoder) { public: @@ -64,44 +60,18 @@ class Impl; friend class RTCVideoEncoder::Impl; - // Return an encoded output buffer to WebRTC. - void ReturnEncodedImage(std::unique_ptr<webrtc::EncodedImage> image, - int32_t bitstream_buffer_id, - uint16_t picture_id); - - void NotifyError(int32_t error); - void RecordInitEncodeUMA(int32_t init_retval, media::VideoCodecProfile profile); - base::ThreadChecker thread_checker_; - - // The video codec type, as reported to WebRTC. - const webrtc::VideoCodecType video_codec_type_; - // Factory for creating VEAs, shared memory buffers, etc. media::GpuVideoAcceleratorFactories* gpu_factories_; // Task runner that the video accelerator runs on. const scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_; - // webrtc::VideoEncoder encode complete callback. - webrtc::EncodedImageCallback* encoded_image_callback_; - // The RTCVideoEncoder::Impl that does all the work. scoped_refptr<Impl> impl_; - // We cannot immediately return error conditions to the WebRTC user of this - // class, as there is no error callback in the webrtc::VideoEncoder interface. - // Instead, we cache an error status here and return it the next time an - // interface entry point is called. - int32_t impl_status_; - - // Weak pointer factory for posting back VEA::Client notifications to - // RTCVideoEncoder. - // NOTE: Weak pointers must be invalidated before all other member variables. - base::WeakPtrFactory<RTCVideoEncoder> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(RTCVideoEncoder); };
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 5fadcf68..4f0d7c6 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1126,7 +1126,7 @@ void RenderFrameImpl::InitializeBlameContext(RenderFrameImpl* parent_frame) { DCHECK(!blame_context_); - blame_context_ = new FrameBlameContext(this, parent_frame); + blame_context_ = base::WrapUnique(new FrameBlameContext(this, parent_frame)); blame_context_->Initialize(); } @@ -2557,7 +2557,7 @@ blink::BlameContext* RenderFrameImpl::frameBlameContext() { DCHECK(blame_context_); - return blame_context_; + return blame_context_.get(); } blink::WebServiceWorkerProvider*
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index eaadfa8..57c67a1 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -1220,7 +1220,7 @@ std::unique_ptr<ExternalPopupMenu> external_popup_menu_; #endif - FrameBlameContext* blame_context_; // Not owned. + std::unique_ptr<FrameBlameContext> blame_context_; base::WeakPtrFactory<RenderFrameImpl> weak_factory_;
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index b141202..8e59d0d 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -288,7 +288,7 @@ "//tools/xdisplaycheck", ] - deps += [ "//ui/events/devices" ] + deps += [ "//ui/events/devices/x11" ] } if (is_android) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index ed2db4eb..9e23c65a 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -868,7 +868,7 @@ [ "../browser/compositor/software_output_device_ozone_unittest.cc" ] } - if (is_mac && use_openssl) { + if (is_mac) { deps += [ "//third_party/boringssl" ] }
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn index ac48f7a..2b86893 100644 --- a/crypto/BUILD.gn +++ b/crypto/BUILD.gn
@@ -19,27 +19,21 @@ "crypto_export.h", "cssm_init.cc", "cssm_init.h", - "curve25519-donna.c", "curve25519.h", - "curve25519_nss.cc", "curve25519_openssl.cc", "ec_private_key.h", - "ec_private_key_nss.cc", "ec_private_key_openssl.cc", "ec_signature_creator.cc", "ec_signature_creator.h", "ec_signature_creator_impl.h", - "ec_signature_creator_nss.cc", "ec_signature_creator_openssl.cc", "encryptor.cc", "encryptor.h", - "encryptor_nss.cc", "encryptor_openssl.cc", "hkdf.cc", "hkdf.h", "hmac.cc", "hmac.h", - "hmac_nss.cc", "hmac_openssl.cc", "mac_security_services_lock.cc", "mac_security_services_lock.h", @@ -66,33 +60,22 @@ "random.cc", "random.h", "rsa_private_key.h", - "rsa_private_key_nss.cc", "rsa_private_key_openssl.cc", "scoped_capi_types.h", "scoped_nss_types.h", "secure_hash.h", - "secure_hash_default.cc", "secure_hash_openssl.cc", "secure_util.cc", "secure_util.h", "sha2.cc", "sha2.h", "signature_creator.h", - "signature_creator_nss.cc", "signature_creator_openssl.cc", "signature_verifier.h", - "signature_verifier_nss.cc", "signature_verifier_openssl.cc", "symmetric_key.h", - "symmetric_key_nss.cc", "symmetric_key_openssl.cc", - "third_party/nss/chromium-blapi.h", - "third_party/nss/chromium-blapit.h", - "third_party/nss/chromium-nss.h", "third_party/nss/chromium-sha256.h", - "third_party/nss/pk11akey.cc", - "third_party/nss/rsawrapr.c", - "third_party/nss/secsign.cc", "third_party/nss/sha512.cc", ] @@ -130,53 +113,8 @@ ] } - if (use_openssl) { - # Remove NSS files when using OpenSSL - sources -= [ - "curve25519-donna.c", - "curve25519_nss.cc", - "ec_private_key_nss.cc", - "ec_signature_creator_nss.cc", - "encryptor_nss.cc", - "hmac_nss.cc", - "rsa_private_key_nss.cc", - "secure_hash_default.cc", - "signature_creator_nss.cc", - "signature_verifier_nss.cc", - "symmetric_key_nss.cc", - "third_party/nss/chromium-blapi.h", - "third_party/nss/chromium-blapit.h", - "third_party/nss/chromium-nss.h", - "third_party/nss/pk11akey.cc", - "third_party/nss/rsawrapr.c", - "third_party/nss/secsign.cc", - ] - } else { - # Remove OpenSSL when using NSS. - sources -= [ - "aead_openssl.cc", - "aead_openssl.h", - "auto_cbb.h", - "curve25519_openssl.cc", - "ec_private_key_openssl.cc", - "ec_signature_creator_openssl.cc", - "encryptor_openssl.cc", - "hmac_openssl.cc", - "openssl_bio_string.cc", - "openssl_bio_string.h", - "openssl_util.cc", - "openssl_util.h", - "rsa_private_key_openssl.cc", - "secure_hash_openssl.cc", - "signature_creator_openssl.cc", - "signature_verifier_openssl.cc", - "symmetric_key_openssl.cc", - ] - } - - # 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) { + # Some files are built when NSS is used for the platform certificate library. + if (!use_nss_certs) { sources -= [ "nss_key_util.cc", "nss_key_util.h", @@ -248,19 +186,14 @@ "symmetric_key_unittest.cc", ] - # 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) { + # Some files are built when NSS is used for the platform certificate library. + if (!use_nss_certs) { sources -= [ "nss_key_util_unittest.cc", "nss_util_unittest.cc", ] } - if (!use_openssl) { - sources -= [ "openssl_bio_string_unittest.cc" ] - } - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ @@ -308,7 +241,7 @@ } config("platform_config") { - if ((!use_openssl || use_nss_certs) && is_clang) { + if (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" ] @@ -319,40 +252,14 @@ # 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) { - public_deps = [ - "//third_party/boringssl", - ] - } else { - public_deps = [ - "//net/third_party/nss/ssl:libssl", - ] - } + public_deps = [ + "//third_party/boringssl", + ] - # 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). - 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. - public_deps += [ - "//third_party/nss:nspr", - "//third_party/nss:nss", - ] - } + # Link in NSS if it is used for the platform certificate library + # (use_nss_certs). + if (use_nss_certs) { + public_configs = [ ":platform_config" ] + public_configs += [ "//third_party/nss:system_nss_no_ssl_config" ] } }
diff --git a/crypto/aead_openssl.cc b/crypto/aead_openssl.cc index 7249421..8ad05dc 100644 --- a/crypto/aead_openssl.cc +++ b/crypto/aead_openssl.cc
@@ -4,8 +4,6 @@ #include "crypto/aead_openssl.h" -#if defined(USE_OPENSSL) - #include <openssl/aes.h> #include <openssl/evp.h> #include <stddef.h> @@ -123,5 +121,3 @@ } } // namespace - -#endif
diff --git a/crypto/aead_openssl_unittest.cc b/crypto/aead_openssl_unittest.cc index 446bca2..395e15a 100644 --- a/crypto/aead_openssl_unittest.cc +++ b/crypto/aead_openssl_unittest.cc
@@ -10,8 +10,6 @@ namespace { -#if defined(USE_OPENSSL) - TEST(AeadTest, SealOpen) { crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); std::string key(aead.KeyLength(), 0); @@ -49,6 +47,4 @@ EXPECT_EQ(0U, decrypted.size()); } -#endif - } // namespace
diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp index 21bd6c5..9edbe356 100644 --- a/crypto/crypto.gyp +++ b/crypto/crypto.gyp
@@ -17,10 +17,17 @@ 'dependencies': [ '../base/base.gyp:base', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '../third_party/boringssl/boringssl.gyp:boringssl', ], 'defines': [ 'CRYPTO_IMPLEMENTATION', ], + 'sources!': [ + 'third_party/nss/chromium-nss.h', + 'third_party/nss/chromium-prtypes.h', + 'third_party/nss/chromium-sha256.h', + 'third_party/nss/sha512.cc', + ], 'conditions': [ [ 'os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', { 'dependencies': [ @@ -70,16 +77,6 @@ 'mac_security_services_lock.h', ], }], - [ 'use_openssl == 0 and (OS == "mac" or OS == "ios" or OS == "win")', { - 'dependencies': [ - '../third_party/nss/nss.gyp:nspr', - '../third_party/nss/nss.gyp:nss', - ], - 'export_dependent_settings': [ - '../third_party/nss/nss.gyp:nspr', - '../third_party/nss/nss.gyp:nss', - ], - }], [ 'OS != "win"', { 'sources!': [ 'capi_util.h', @@ -91,58 +88,8 @@ 4267, # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. ], }], - [ 'use_openssl==1', { - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - # TODO(joth): Use a glob to match exclude patterns once the - # OpenSSL file set is complete. - 'sources!': [ - 'curve25519-donna.c', - 'curve25519_nss.cc', - 'ec_private_key_nss.cc', - 'ec_signature_creator_nss.cc', - 'encryptor_nss.cc', - 'hmac_nss.cc', - 'rsa_private_key_nss.cc', - 'secure_hash_default.cc', - 'signature_creator_nss.cc', - 'signature_verifier_nss.cc', - 'symmetric_key_nss.cc', - 'third_party/nss/chromium-blapi.h', - 'third_party/nss/chromium-blapit.h', - 'third_party/nss/chromium-nss.h', - 'third_party/nss/chromium-prtypes.h', - 'third_party/nss/chromium-sha256.h', - 'third_party/nss/pk11akey.cc', - 'third_party/nss/rsawrapr.c', - 'third_party/nss/secsign.cc', - 'third_party/nss/sha512.cc', - ], - }, { - 'sources!': [ - 'aead_openssl.cc', - 'aead_openssl.h', - 'auto_cbb.h', - 'curve25519_openssl.cc', - 'ec_private_key_openssl.cc', - 'ec_signature_creator_openssl.cc', - 'encryptor_openssl.cc', - 'hmac_openssl.cc', - 'openssl_bio_string.cc', - 'openssl_bio_string.h', - 'openssl_util.cc', - 'openssl_util.h', - 'rsa_private_key_openssl.cc', - 'secure_hash_openssl.cc', - 'signature_creator_openssl.cc', - 'signature_verifier_openssl.cc', - '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. + [ 'use_nss_certs==0', { + # Some files are built when NSS is used for the platform certificate library. 'sources!': [ 'nss_key_util.cc', 'nss_key_util.h', @@ -188,6 +135,7 @@ '../base/base.gyp:test_support_base', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', + '../third_party/boringssl/boringssl.gyp:boringssl', ], 'conditions': [ [ 'use_nss_certs == 1', { @@ -195,32 +143,17 @@ '../build/linux/system.gyp:ssl', ], }], - [ '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. + [ 'use_nss_certs == 0', { + # Some files are built when NSS is used for the platform certificate library. 'sources!': [ 'nss_key_util_unittest.cc', 'nss_util_unittest.cc', ], }], - [ 'use_openssl == 0 and (OS == "mac" or OS == "ios" or OS == "win")', { - 'dependencies': [ - '../third_party/nss/nss.gyp:nspr', - ], - }], [ 'OS == "win"', { # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. 'msvs_disabled_warnings': [4267, ], }], - [ 'use_openssl==1', { - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - }, { - 'sources!': [ - 'openssl_bio_string_unittest.cc', - ], - }], ], }, ], @@ -229,9 +162,7 @@ 'targets': [ { 'target_name': 'crypto_nacl_win64', - # We do not want nacl_helper to depend on NSS because this would - # require including a 64-bit copy of NSS. Thus, use the native APIs - # for the helper. + # We use the native APIs for the helper. 'type': '<(component)', 'dependencies': [ '../base/base.gyp:base_win64',
diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi index a7135cf6..748f4a9 100644 --- a/crypto/crypto.gypi +++ b/crypto/crypto.gypi
@@ -15,8 +15,6 @@ 'secure_util.h', 'symmetric_key.h', 'symmetric_key_win.cc', - 'third_party/nss/chromium-blapi.h', - 'third_party/nss/chromium-blapit.h', 'third_party/nss/chromium-prtypes.h', 'third_party/nss/chromium-sha256.h', 'third_party/nss/sha512.cc', @@ -38,25 +36,19 @@ 'crypto_export.h', 'cssm_init.cc', 'cssm_init.h', - 'curve25519-donna.c', 'curve25519.h', - 'curve25519_nss.cc', 'curve25519_openssl.cc', 'ec_private_key.h', - 'ec_private_key_nss.cc', 'ec_private_key_openssl.cc', 'ec_signature_creator.cc', 'ec_signature_creator.h', 'ec_signature_creator_impl.h', - 'ec_signature_creator_nss.cc', 'ec_signature_creator_openssl.cc', 'encryptor.cc', 'encryptor.h', - 'encryptor_nss.cc', 'encryptor_openssl.cc', 'hkdf.cc', 'hkdf.h', - 'hmac_nss.cc', 'hmac_openssl.cc', 'mac_security_services_lock.cc', 'mac_security_services_lock.h', @@ -81,27 +73,18 @@ 'random.h', 'random.cc', 'rsa_private_key.h', - 'rsa_private_key_nss.cc', 'rsa_private_key_openssl.cc', 'scoped_capi_types.h', 'scoped_nss_types.h', 'secure_hash.h', - 'secure_hash_default.cc', 'secure_hash_openssl.cc', 'sha2.cc', 'sha2.h', 'signature_creator.h', - 'signature_creator_nss.cc', 'signature_creator_openssl.cc', 'signature_verifier.h', - 'signature_verifier_nss.cc', 'signature_verifier_openssl.cc', - 'symmetric_key_nss.cc', 'symmetric_key_openssl.cc', - 'third_party/nss/chromium-nss.h', - 'third_party/nss/pk11akey.cc', - 'third_party/nss/rsawrapr.c', - 'third_party/nss/secsign.cc', ], 'nacl_win64_sources': [ '<@(hmac_win64_related_sources)',
diff --git a/crypto/curve25519-donna.c b/crypto/curve25519-donna.c deleted file mode 100644 index f141ac0..0000000 --- a/crypto/curve25519-donna.c +++ /dev/null
@@ -1,592 +0,0 @@ -// Copyright (c) 2013 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. - -/* - * curve25519-donna: Curve25519 elliptic curve, public key function - * - * http://code.google.com/p/curve25519-donna/ - * - * Adam Langley <agl@imperialviolet.org> - * - * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to> - * - * More information about curve25519 can be found here - * http://cr.yp.to/ecdh.html - * - * djb's sample implementation of curve25519 is written in a special assembly - * language called qhasm and uses the floating point registers. - * - * This is, almost, a clean room reimplementation from the curve25519 paper. It - * uses many of the tricks described therein. Only the crecip function is taken - * from the sample implementation. - */ - -#include <string.h> -#include <stdint.h> - -typedef uint8_t u8; -typedef int32_t s32; -typedef int64_t limb; - -/* Field element representation: - * - * Field elements are written as an array of signed, 64-bit limbs, least - * significant first. The value of the field element is: - * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... - * - * i.e. the limbs are 26, 25, 26, 25, ... bits wide. - */ - -/* Sum two numbers: output += in */ -static void fsum(limb *output, const limb *in) { - unsigned i; - for (i = 0; i < 10; i += 2) { - output[0+i] = (output[0+i] + in[0+i]); - output[1+i] = (output[1+i] + in[1+i]); - } -} - -/* Find the difference of two numbers: output = in - output - * (note the order of the arguments!) - */ -static void fdifference(limb *output, const limb *in) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = (in[i] - output[i]); - } -} - -/* Multiply a number my a scalar: output = in * scalar */ -static void fscalar_product(limb *output, const limb *in, const limb scalar) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] * scalar; - } -} - -/* Multiply two numbers: output = in2 * in - * - * output must be distinct to both inputs. The inputs are reduced coefficient - * form, the output is not. - */ -static void fproduct(limb *output, const limb *in2, const limb *in) { - output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); - output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + - ((limb) ((s32) in2[1])) * ((s32) in[0]); - output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[0]); - output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[0]); - output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + - 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[1])) + - ((limb) ((s32) in2[0])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[0]); - output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[0]); - output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[0]); - output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[0]); - output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[0]); - output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[0]); - output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[1])) + - ((limb) ((s32) in2[4])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[4]) + - ((limb) ((s32) in2[2])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[2]); - output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[2]); - output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[3])) + - ((limb) ((s32) in2[4])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[4]); - output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[6]) + - ((limb) ((s32) in2[5])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[4]); - output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + - ((limb) ((s32) in2[5])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[5])) + - ((limb) ((s32) in2[6])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[6]); - output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[7]) + - ((limb) ((s32) in2[6])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[6]); - output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[7])); - output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[8]); - output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); -} - -/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */ -static void freduce_degree(limb *output) { - /* Each of these shifts and adds ends up multiplying the value by 19. */ - output[8] += output[18] << 4; - output[8] += output[18] << 1; - output[8] += output[18]; - output[7] += output[17] << 4; - output[7] += output[17] << 1; - output[7] += output[17]; - output[6] += output[16] << 4; - output[6] += output[16] << 1; - output[6] += output[16]; - output[5] += output[15] << 4; - output[5] += output[15] << 1; - output[5] += output[15]; - output[4] += output[14] << 4; - output[4] += output[14] << 1; - output[4] += output[14]; - output[3] += output[13] << 4; - output[3] += output[13] << 1; - output[3] += output[13]; - output[2] += output[12] << 4; - output[2] += output[12] << 1; - output[2] += output[12]; - output[1] += output[11] << 4; - output[1] += output[11] << 1; - output[1] += output[11]; - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; -} - -/* Reduce all coefficients of the short form input so that |x| < 2^26. - * - * On entry: |output[i]| < 2^62 - */ -static void freduce_coefficients(limb *output) { - unsigned i; - do { - output[10] = 0; - - for (i = 0; i < 10; i += 2) { - limb over = output[i] / 0x4000000l; - output[i+1] += over; - output[i] -= over * 0x4000000l; - - over = output[i+1] / 0x2000000; - output[i+2] += over; - output[i+1] -= over * 0x2000000; - } - output[0] += 19 * output[10]; - } while (output[10]); -} - -/* A helpful wrapper around fproduct: output = in * in2. - * - * output must be distinct to both inputs. The output is reduced degree and - * reduced coefficient. - */ -static void -fmul(limb *output, const limb *in, const limb *in2) { - limb t[19]; - fproduct(t, in, in2); - freduce_degree(t); - freduce_coefficients(t); - memcpy(output, t, sizeof(limb) * 10); -} - -static void fsquare_inner(limb *output, const limb *in) { - output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); - output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); - output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + - ((limb) ((s32) in[0])) * ((s32) in[2])); - output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + - ((limb) ((s32) in[0])) * ((s32) in[3])); - output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + - 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + - 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); - output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + - ((limb) ((s32) in[1])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[5])); - output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + - ((limb) ((s32) in[2])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[6]) + - 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); - output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + - ((limb) ((s32) in[2])) * ((s32) in[5]) + - ((limb) ((s32) in[1])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[7])); - output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[5]))); - output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + - ((limb) ((s32) in[3])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[8]) + - ((limb) ((s32) in[0])) * ((s32) in[9])); - output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + - ((limb) ((s32) in[4])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[9]))); - output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + - ((limb) ((s32) in[4])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[8]) + - ((limb) ((s32) in[2])) * ((s32) in[9])); - output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[9]))); - output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + - ((limb) ((s32) in[5])) * ((s32) in[8]) + - ((limb) ((s32) in[4])) * ((s32) in[9])); - output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + - ((limb) ((s32) in[6])) * ((s32) in[8]) + - 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); - output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + - ((limb) ((s32) in[6])) * ((s32) in[9])); - output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + - 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); - output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); - output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); -} - -static void -fsquare(limb *output, const limb *in) { - limb t[19]; - fsquare_inner(t, in); - freduce_degree(t); - freduce_coefficients(t); - memcpy(output, t, sizeof(limb) * 10); -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -fexpand(limb *output, const u8 *input) { -#define F(n,start,shift,mask) \ - output[n] = ((((limb) input[start + 0]) | \ - ((limb) input[start + 1]) << 8 | \ - ((limb) input[start + 2]) << 16 | \ - ((limb) input[start + 3]) << 24) >> shift) & mask; - F(0, 0, 0, 0x3ffffff); - F(1, 3, 2, 0x1ffffff); - F(2, 6, 3, 0x3ffffff); - F(3, 9, 5, 0x1ffffff); - F(4, 12, 6, 0x3ffffff); - F(5, 16, 0, 0x1ffffff); - F(6, 19, 1, 0x3ffffff); - F(7, 22, 3, 0x1ffffff); - F(8, 25, 4, 0x3ffffff); - F(9, 28, 6, 0x1ffffff); -#undef F -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -static void -fcontract(u8 *output, limb *input) { - int i; - - do { - for (i = 0; i < 9; ++i) { - if ((i & 1) == 1) { - while (input[i] < 0) { - input[i] += 0x2000000; - input[i + 1]--; - } - } else { - while (input[i] < 0) { - input[i] += 0x4000000; - input[i + 1]--; - } - } - } - while (input[9] < 0) { - input[9] += 0x2000000; - input[0] -= 19; - } - } while (input[0] < 0); - - input[1] <<= 2; - input[2] <<= 3; - input[3] <<= 5; - input[4] <<= 6; - input[6] <<= 1; - input[7] <<= 3; - input[8] <<= 4; - input[9] <<= 6; -#define F(i, s) \ - output[s+0] |= input[i] & 0xff; \ - output[s+1] = (input[i] >> 8) & 0xff; \ - output[s+2] = (input[i] >> 16) & 0xff; \ - output[s+3] = (input[i] >> 24) & 0xff; - output[0] = 0; - output[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); -#undef F -} - -/* Input: Q, Q', Q-Q' - * Output: 2Q, Q+Q' - * - * x2 z3: long form - * x3 z3: long form - * x z: short form, destroyed - * xprime zprime: short form, destroyed - * qmqp: short form, preserved - */ -static void fmonty(limb *x2, limb *z2, /* output 2Q */ - limb *x3, limb *z3, /* output Q + Q' */ - limb *x, limb *z, /* input Q */ - limb *xprime, limb *zprime, /* input Q' */ - const limb *qmqp /* input Q - Q' */) { - limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], - zzprime[19], zzzprime[19], xxxprime[19]; - - memcpy(origx, x, 10 * sizeof(limb)); - fsum(x, z); - fdifference(z, origx); // does x - z - - memcpy(origxprime, xprime, sizeof(limb) * 10); - fsum(xprime, zprime); - fdifference(zprime, origxprime); - fproduct(xxprime, xprime, z); - fproduct(zzprime, x, zprime); - freduce_degree(xxprime); - freduce_coefficients(xxprime); - freduce_degree(zzprime); - freduce_coefficients(zzprime); - memcpy(origxprime, xxprime, sizeof(limb) * 10); - fsum(xxprime, zzprime); - fdifference(zzprime, origxprime); - fsquare(xxxprime, xxprime); - fsquare(zzzprime, zzprime); - fproduct(zzprime, zzzprime, qmqp); - freduce_degree(zzprime); - freduce_coefficients(zzprime); - memcpy(x3, xxxprime, sizeof(limb) * 10); - memcpy(z3, zzprime, sizeof(limb) * 10); - - fsquare(xx, x); - fsquare(zz, z); - fproduct(x2, xx, zz); - freduce_degree(x2); - freduce_coefficients(x2); - fdifference(zz, xx); // does zz = xx - zz - memset(zzz + 10, 0, sizeof(limb) * 9); - fscalar_product(zzz, zz, 121665); - freduce_degree(zzz); - freduce_coefficients(zzz); - fsum(zzz, xx); - fproduct(z2, zz, zzz); - freduce_degree(z2); - freduce_coefficients(z2); -} - -/* Calculates nQ where Q is the x-coordinate of a point on the curve - * - * resultx/resultz: the x coordinate of the resulting curve point (short form) - * n: a little endian, 32-byte number - * q: a point of the curve (short form) - */ -static void -cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { - limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; - limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; - limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; - limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; - - unsigned i, j; - - memcpy(nqpqx, q, sizeof(limb) * 10); - - for (i = 0; i < 32; ++i) { - u8 byte = n[31 - i]; - for (j = 0; j < 8; ++j) { - if (byte & 0x80) { - fmonty(nqpqx2, nqpqz2, - nqx2, nqz2, - nqpqx, nqpqz, - nqx, nqz, - q); - } else { - fmonty(nqx2, nqz2, - nqpqx2, nqpqz2, - nqx, nqz, - nqpqx, nqpqz, - q); - } - - t = nqx; - nqx = nqx2; - nqx2 = t; - t = nqz; - nqz = nqz2; - nqz2 = t; - t = nqpqx; - nqpqx = nqpqx2; - nqpqx2 = t; - t = nqpqz; - nqpqz = nqpqz2; - nqpqz2 = t; - - byte <<= 1; - } - } - - memcpy(resultx, nqx, sizeof(limb) * 10); - memcpy(resultz, nqz, sizeof(limb) * 10); -} - -// ----------------------------------------------------------------------------- -// Shamelessly copied from djb's code -// ----------------------------------------------------------------------------- -static void -crecip(limb *out, const limb *z) { - limb z2[10]; - limb z9[10]; - limb z11[10]; - limb z2_5_0[10]; - limb z2_10_0[10]; - limb z2_20_0[10]; - limb z2_50_0[10]; - limb z2_100_0[10]; - limb t0[10]; - limb t1[10]; - int i; - - /* 2 */ fsquare(z2,z); - /* 4 */ fsquare(t1,z2); - /* 8 */ fsquare(t0,t1); - /* 9 */ fmul(z9,t0,z); - /* 11 */ fmul(z11,z9,z2); - /* 22 */ fsquare(t0,z11); - /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); - - /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); - /* 2^7 - 2^2 */ fsquare(t1,t0); - /* 2^8 - 2^3 */ fsquare(t0,t1); - /* 2^9 - 2^4 */ fsquare(t1,t0); - /* 2^10 - 2^5 */ fsquare(t0,t1); - /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); - - /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); - /* 2^12 - 2^2 */ fsquare(t1,t0); - /* 2^20 - 2^10 */ - for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); - - /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); - /* 2^22 - 2^2 */ fsquare(t1,t0); - /* 2^40 - 2^20 */ - for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); - - /* 2^41 - 2^1 */ fsquare(t1,t0); - /* 2^42 - 2^2 */ fsquare(t0,t1); - /* 2^50 - 2^10 */ - for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); - - /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); - /* 2^52 - 2^2 */ fsquare(t1,t0); - /* 2^100 - 2^50 */ - for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); - - /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); - /* 2^102 - 2^2 */ fsquare(t0,t1); - /* 2^200 - 2^100 */ - for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); - - /* 2^201 - 2^1 */ fsquare(t0,t1); - /* 2^202 - 2^2 */ fsquare(t1,t0); - /* 2^250 - 2^50 */ - for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); - - /* 2^251 - 2^1 */ fsquare(t1,t0); - /* 2^252 - 2^2 */ fsquare(t0,t1); - /* 2^253 - 2^3 */ fsquare(t1,t0); - /* 2^254 - 2^4 */ fsquare(t0,t1); - /* 2^255 - 2^5 */ fsquare(t1,t0); - /* 2^255 - 21 */ fmul(out,t1,z11); -} - -int -curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { - limb bp[10], x[10], z[10], zmone[10]; - uint8_t e[32]; - int i; - - for (i = 0; i < 32; ++i) e[i] = secret[i]; - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; - - fexpand(bp, basepoint); - cmult(x, z, e, bp); - crecip(zmone, z); - fmul(z, x, zmone); - fcontract(mypublic, z); - return 0; -}
diff --git a/crypto/curve25519_nss.cc b/crypto/curve25519_nss.cc deleted file mode 100644 index 88bf94c..0000000 --- a/crypto/curve25519_nss.cc +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2013 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/curve25519.h" - -#include <stdint.h> - -#include "crypto/secure_util.h" - -// Curve25519 is specified in terms of byte strings, not numbers, so all -// implementations take and return the same sequence of bits. So the byte -// order is implicitly specified as in, say, SHA1. -// -// Prototype for |curve25519_donna| function in -// third_party/curve25519-donna/curve25519-donna.c -extern "C" int curve25519_donna(uint8_t*, const uint8_t*, const uint8_t*); - -namespace crypto { - -namespace curve25519 { - -bool ScalarMult(const uint8_t* private_key, - const uint8_t* peer_public_key, - uint8_t* shared_key) { - curve25519_donna(shared_key, private_key, peer_public_key); - - // The all-zero output results when the input is a point of small order. - static const uint8_t kZeros[32] = {0}; - return !SecureMemEqual(shared_key, kZeros, 32); -} - -// kBasePoint is the base point (generator) of the elliptic curve group. -// It is little-endian version of '9' followed by 31 zeros. -// See "Computing public keys" section of http://cr.yp.to/ecdh.html. -static const uint8_t kBasePoint[32] = {9}; - -void ScalarBaseMult(const uint8_t* private_key, uint8_t* public_key) { - curve25519_donna(public_key, private_key, kBasePoint); -} - -} // namespace curve25519 - -} // namespace crypto
diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h index 1ee4aca..6ebe21d 100644 --- a/crypto/ec_private_key.h +++ b/crypto/ec_private_key.h
@@ -15,16 +15,8 @@ #include "build/build_config.h" #include "crypto/crypto_export.h" -#if defined(USE_OPENSSL) // Forward declaration for openssl/*.h typedef struct evp_pkey_st EVP_PKEY; -#else -// Forward declaration. -typedef struct CERTSubjectPublicKeyInfoStr CERTSubjectPublicKeyInfo; -typedef struct PK11SlotInfoStr PK11SlotInfo; -typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey; -typedef struct SECKEYPublicKeyStr SECKEYPublicKey; -#endif namespace crypto { @@ -51,32 +43,10 @@ const std::vector<uint8_t>& encrypted_private_key_info, const std::vector<uint8_t>& subject_public_key_info); -#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 - // without having to create a ECPrivateKey object and make a copy of them. - // TODO(mattm): move this function to some NSS util file. - static bool ImportFromEncryptedPrivateKeyInfo( - PK11SlotInfo* slot, - const std::string& password, - const uint8_t* encrypted_private_key_info, - size_t encrypted_private_key_info_len, - CERTSubjectPublicKeyInfo* decoded_spki, - bool permanent, - bool sensitive, - SECKEYPrivateKey** key, - SECKEYPublicKey** public_key); -#endif - // Returns a copy of the object. ECPrivateKey* Copy() const; -#if defined(USE_OPENSSL) EVP_PKEY* key() { return key_; } -#else - SECKEYPrivateKey* key() { return key_; } - SECKEYPublicKey* public_key() { return public_key_; } -#endif // Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo // block and the public key as an X.509 SubjectPublicKeyInfo block. @@ -101,12 +71,7 @@ // Constructor is private. Use one of the Create*() methods above instead. ECPrivateKey(); -#if defined(USE_OPENSSL) EVP_PKEY* key_; -#else - SECKEYPrivateKey* key_; - SECKEYPublicKey* public_key_; -#endif DISALLOW_COPY_AND_ASSIGN(ECPrivateKey); };
diff --git a/crypto/ec_private_key_nss.cc b/crypto/ec_private_key_nss.cc deleted file mode 100644 index 8ca8f25ec..0000000 --- a/crypto/ec_private_key_nss.cc +++ /dev/null
@@ -1,326 +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. - -#include "crypto/ec_private_key.h" - -extern "C" { -// Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before -// other NSS headers. -#include <secmodt.h> -} - -#include <cryptohi.h> -#include <keyhi.h> -#include <pk11pub.h> -#include <secmod.h> -#include <stddef.h> -#include <stdint.h> - -#include <memory> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/nss_util_internal.h" -#include "crypto/scoped_nss_types.h" -#include "crypto/third_party/nss/chromium-nss.h" - -namespace { - -static bool AppendAttribute(SECKEYPrivateKey* key, - CK_ATTRIBUTE_TYPE type, - std::vector<uint8_t>* output) { - SECItem item; - SECStatus rv; - rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); - if (rv != SECSuccess) { - DLOG(ERROR) << "PK11_ReadRawAttribute: " << PORT_GetError(); - return false; - } - - output->insert(output->end(), item.data, item.data + item.len); - SECITEM_FreeItem(&item, PR_FALSE); - return true; -} - -} // namespace - -namespace crypto { - -ECPrivateKey::~ECPrivateKey() { - if (key_) - SECKEY_DestroyPrivateKey(key_); - if (public_key_) - SECKEY_DestroyPublicKey(public_key_); -} - -// static -ECPrivateKey* ECPrivateKey::Create() { - EnsureNSSInit(); - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - if (!slot) - return nullptr; - - std::unique_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(); -} - -// static -ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - const std::string& password, - const std::vector<uint8_t>& encrypted_private_key_info, - const std::vector<uint8_t>& subject_public_key_info) { - EnsureNSSInit(); - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - if (!slot) - return nullptr; - - std::unique_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[0], - encrypted_private_key_info.size(), - decoded_spki, - false /* not permanent */, - false /* not sensitive */, - &result->key_, - &result->public_key_); - - SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); - - if (success) { - CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_)); - return result.release(); - } - - return nullptr; -} - -// static -bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo( - PK11SlotInfo* slot, - const std::string& password, - const uint8_t* encrypted_private_key_info, - size_t encrypted_private_key_info_len, - CERTSubjectPublicKeyInfo* decoded_spki, - bool permanent, - bool sensitive, - SECKEYPrivateKey** key, - SECKEYPublicKey** public_key) { - if (!slot) - return false; - - *public_key = SECKEY_ExtractPublicKey(decoded_spki); - - if (!*public_key) { - DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError(); - return false; - } - - if (SECKEY_GetPublicKeyType(*public_key) != ecKey) { - DLOG(ERROR) << "The public key is not an EC key"; - SECKEY_DestroyPublicKey(*public_key); - *public_key = NULL; - return false; - } - - SECItem encoded_epki = { - siBuffer, - const_cast<unsigned char*>(encrypted_private_key_info), - static_cast<unsigned>(encrypted_private_key_info_len) - }; - SECKEYEncryptedPrivateKeyInfo epki; - memset(&epki, 0, sizeof(epki)); - - ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - - SECStatus rv = SEC_QuickDERDecodeItem( - arena.get(), - &epki, - SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), - &encoded_epki); - if (rv != SECSuccess) { - DLOG(ERROR) << "SEC_QuickDERDecodeItem: " << PORT_GetError(); - SECKEY_DestroyPublicKey(*public_key); - *public_key = NULL; - return false; - } - - SECItem password_item = { - siBuffer, - reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), - static_cast<unsigned>(password.size()) - }; - - rv = ImportEncryptedECPrivateKeyInfoAndReturnKey( - slot, - &epki, - &password_item, - NULL, // nickname - &(*public_key)->u.ec.publicValue, - permanent, - sensitive, - key, - NULL); // wincx - if (rv != SECSuccess) { - DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: " - << PORT_GetError(); - SECKEY_DestroyPublicKey(*public_key); - *public_key = NULL; - return false; - } - - return true; -} - -ECPrivateKey* ECPrivateKey::Copy() const { - std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey); - if (key_) { - copy->key_ = SECKEY_CopyPrivateKey(key_); - if (!copy->key_) - return NULL; - } - if (public_key_) { - copy->public_key_ = SECKEY_CopyPublicKey(public_key_); - if (!copy->public_key_) - return NULL; - } - return copy.release(); -} - -bool ECPrivateKey::ExportEncryptedPrivateKey(const std::string& password, - int iterations, - std::vector<uint8_t>* output) { - // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8 - // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't - // support EC keys. - // https://bugzilla.mozilla.org/show_bug.cgi?id=327773 - SECItem password_item = { - siBuffer, - reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), - static_cast<unsigned>(password.size()) - }; - - SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo( - NULL, // Slot, optional. - SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC, - &password_item, - key_, - iterations, - NULL); // wincx. - - if (!encrypted) { - DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError(); - return false; - } - - ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - SECItem der_key = {siBuffer, NULL, 0}; - SECItem* encoded_item = SEC_ASN1EncodeItem( - arena.get(), - &der_key, - encrypted, - SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate)); - SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE); - if (!encoded_item) { - DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError(); - return false; - } - - output->assign(der_key.data, der_key.data + der_key.len); - - return true; -} - -bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) { - ScopedSECItem der_pubkey( - SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_)); - if (!der_pubkey.get()) { - return false; - } - - output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len); - return true; -} - -bool ECPrivateKey::ExportRawPublicKey(std::string* output) { - // public_key_->u.ec.publicValue is an ANSI X9.62 public key which, for - // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field - // elements as 32-byte, big-endian numbers. - static const unsigned int kExpectedKeyLength = 65; - - CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(public_key_)); - const unsigned char* const data = public_key_->u.ec.publicValue.data; - const unsigned int len = public_key_->u.ec.publicValue.len; - if (len != kExpectedKeyLength || data[0] != 0x04) - return false; - - output->assign(reinterpret_cast<const char*>(data + 1), - kExpectedKeyLength - 1); - return true; -} - -bool ECPrivateKey::ExportValueForTesting(std::vector<uint8_t>* output) { - // This serialization format is purely for testing equality, so just - // concatenate the raw private key (always 32 bytes for P-256) with the - // parameters. - output->clear(); - return AppendAttribute(key_, CKA_VALUE, output) && - output->size() == 32 && - AppendAttribute(key_, CKA_EC_PARAMS, output); -} - -ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {} - -} // namespace crypto
diff --git a/crypto/ec_private_key_unittest.cc b/crypto/ec_private_key_unittest.cc index 0fa8c8c..00bd77c 100644 --- a/crypto/ec_private_key_unittest.cc +++ b/crypto/ec_private_key_unittest.cc
@@ -223,7 +223,6 @@ // The Android code writes out Channel IDs differently from the NSS // implementation; the empty password is converted to "\0\0". The OpenSSL port // should support either. -#if defined(USE_OPENSSL) TEST(ECPrivateKeyUnitTest, LoadOldOpenSSLKeyTest) { static const uint8_t kOpenSSLKey[] = { 0x30, 0x82, 0x01, 0xa1, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, @@ -303,4 +302,3 @@ EXPECT_TRUE(keypair_openssl.get()); } -#endif // defined(USE_OPENSSL)
diff --git a/crypto/ec_signature_creator_nss.cc b/crypto/ec_signature_creator_nss.cc deleted file mode 100644 index 7c8cc7d..0000000 --- a/crypto/ec_signature_creator_nss.cc +++ /dev/null
@@ -1,116 +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. - -#include "crypto/ec_signature_creator_impl.h" - -#include <cryptohi.h> -#include <pk11pub.h> -#include <secerr.h> -#include <sechash.h> -#if defined(OS_POSIX) -#include <stddef.h> -#include <stdint.h> -#include <unistd.h> -#endif - -#include "base/logging.h" -#include "crypto/ec_private_key.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" - -namespace crypto { - -namespace { - -SECStatus SignData(SECItem* result, - SECItem* input, - SECKEYPrivateKey* key, - HASH_HashType hash_type) { - if (key->keyType != ecKey) { - DLOG(FATAL) << "Should be using an EC key."; - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - // Hash the input. - std::vector<uint8_t> hash_data(HASH_ResultLen(hash_type)); - SECStatus rv = HASH_HashBuf( - hash_type, &hash_data[0], input->data, input->len); - if (rv != SECSuccess) - return rv; - SECItem hash = {siBuffer, &hash_data[0], - static_cast<unsigned int>(hash_data.size())}; - - // Compute signature of hash. - int signature_len = PK11_SignatureLen(key); - std::vector<uint8_t> signature_data(signature_len); - SECItem sig = {siBuffer, &signature_data[0], - static_cast<unsigned int>(signature_len)}; - rv = PK11_Sign(key, &sig, &hash); - if (rv != SECSuccess) - return rv; - - // DER encode the signature. - return DSAU_EncodeDerSigWithLen(result, &sig, sig.len); -} - -} // namespace - -ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key) - : key_(key) { - EnsureNSSInit(); -} - -ECSignatureCreatorImpl::~ECSignatureCreatorImpl() {} - -bool ECSignatureCreatorImpl::Sign(const uint8_t* data, - int data_len, - std::vector<uint8_t>* signature) { - // Data to be signed - SECItem secret; - secret.type = siBuffer; - secret.len = data_len; - secret.data = const_cast<unsigned char*>(data); - - // SECItem to receive the output buffer. - SECItem result; - result.type = siBuffer; - result.len = 0; - result.data = NULL; - - // Sign the secret data and save it to |result|. - SECStatus rv = - SignData(&result, &secret, key_->key(), HASH_AlgSHA256); - if (rv != SECSuccess) { - DLOG(ERROR) << "DerSignData: " << PORT_GetError(); - return false; - } - - // Copy the signed data into the output vector. - signature->assign(result.data, result.data + result.len); - SECITEM_FreeItem(&result, PR_FALSE /* only free |result.data| */); - return true; -} - -bool ECSignatureCreatorImpl::DecodeSignature( - const std::vector<uint8_t>& der_sig, - std::vector<uint8_t>* out_raw_sig) { - SECItem der_sig_item; - der_sig_item.type = siBuffer; - der_sig_item.len = der_sig.size(); - der_sig_item.data = const_cast<uint8_t*>(&der_sig[0]); - - size_t signature_len = SECKEY_SignatureLen(key_->public_key()); - if (signature_len == 0) - return false; - - SECItem* raw_sig = DSAU_DecodeDerSigToLen(&der_sig_item, signature_len); - if (!raw_sig) - return false; - out_raw_sig->assign(raw_sig->data, raw_sig->data + raw_sig->len); - SECITEM_FreeItem(raw_sig, PR_TRUE /* free SECItem structure itself. */); - return true; -} - -} // namespace crypto
diff --git a/crypto/encryptor.h b/crypto/encryptor.h index f1a478a..f5a1031 100644 --- a/crypto/encryptor.h +++ b/crypto/encryptor.h
@@ -15,10 +15,6 @@ #include "build/build_config.h" #include "crypto/crypto_export.h" -#if !defined(USE_OPENSSL) -#include "crypto/scoped_nss_types.h" -#endif - namespace crypto { class SymmetricKey; @@ -115,7 +111,6 @@ Mode mode_; std::unique_ptr<Counter> counter_; -#if defined(USE_OPENSSL) bool Crypt(bool do_encrypt, // Pass true to encrypt, false to decrypt. const base::StringPiece& input, std::string* output); @@ -123,15 +118,6 @@ const base::StringPiece& input, std::string* output); std::string iv_; -#else - bool Crypt(PK11Context* context, - const base::StringPiece& input, - std::string* output); - bool CryptCTR(PK11Context* context, - const base::StringPiece& input, - std::string* output); - ScopedSECItem param_; -#endif }; } // namespace crypto
diff --git a/crypto/encryptor_nss.cc b/crypto/encryptor_nss.cc deleted file mode 100644 index eca1377..0000000 --- a/crypto/encryptor_nss.cc +++ /dev/null
@@ -1,203 +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/encryptor.h" - -#include <cryptohi.h> -#include <stddef.h> -#include <stdint.h> -#include <vector> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/symmetric_key.h" - -namespace crypto { - -namespace { - -inline CK_MECHANISM_TYPE GetMechanism(Encryptor::Mode mode) { - switch (mode) { - case Encryptor::CBC: - return CKM_AES_CBC_PAD; - case Encryptor::CTR: - // AES-CTR encryption uses ECB encryptor as a building block since - // NSS doesn't support CTR encryption mode. - return CKM_AES_ECB; - default: - NOTREACHED() << "Unsupported mode of operation"; - break; - } - return static_cast<CK_MECHANISM_TYPE>(-1); -} - -} // namespace - -Encryptor::Encryptor() - : key_(NULL), - mode_(CBC) { - EnsureNSSInit(); -} - -Encryptor::~Encryptor() { -} - -bool Encryptor::Init(SymmetricKey* key, - Mode mode, - const base::StringPiece& iv) { - DCHECK(key); - DCHECK(CBC == mode || CTR == mode) << "Unsupported mode of operation"; - - key_ = key; - mode_ = mode; - - if (mode == CBC && iv.size() != AES_BLOCK_SIZE) - return false; - - switch (mode) { - case CBC: - SECItem iv_item; - iv_item.type = siBuffer; - iv_item.data = reinterpret_cast<unsigned char*>( - const_cast<char *>(iv.data())); - iv_item.len = iv.size(); - - param_.reset(PK11_ParamFromIV(GetMechanism(mode), &iv_item)); - break; - case CTR: - param_.reset(PK11_ParamFromIV(GetMechanism(mode), NULL)); - break; - } - - return param_ != NULL; -} - -bool Encryptor::Encrypt(const base::StringPiece& plaintext, - std::string* ciphertext) { - CHECK(!plaintext.empty() || (mode_ == CBC)); - ScopedPK11Context context(PK11_CreateContextBySymKey(GetMechanism(mode_), - CKA_ENCRYPT, - key_->key(), - param_.get())); - if (!context.get()) - return false; - - return (mode_ == CTR) ? - CryptCTR(context.get(), plaintext, ciphertext) : - Crypt(context.get(), plaintext, ciphertext); -} - -bool Encryptor::Decrypt(const base::StringPiece& ciphertext, - std::string* plaintext) { - CHECK(!ciphertext.empty()); - ScopedPK11Context context(PK11_CreateContextBySymKey( - GetMechanism(mode_), (mode_ == CTR ? CKA_ENCRYPT : CKA_DECRYPT), - key_->key(), param_.get())); - if (!context.get()) - return false; - - if (mode_ == CTR) - return CryptCTR(context.get(), ciphertext, plaintext); - - if (ciphertext.size() % AES_BLOCK_SIZE != 0) { - // Decryption will fail if the input is not a multiple of the block size. - // PK11_CipherOp has a bug where it will do an invalid memory access before - // the start of the input, so avoid calling it. (NSS bug 922780). - plaintext->clear(); - return false; - } - - return Crypt(context.get(), ciphertext, plaintext); -} - -bool Encryptor::Crypt(PK11Context* context, - const base::StringPiece& input, - std::string* output) { - size_t output_len = input.size() + AES_BLOCK_SIZE; - CHECK_GT(output_len, input.size()); - - output->resize(output_len); - uint8_t* output_data = - reinterpret_cast<uint8_t*>(const_cast<char*>(output->data())); - - int input_len = input.size(); - uint8_t* input_data = - reinterpret_cast<uint8_t*>(const_cast<char*>(input.data())); - - int op_len; - SECStatus rv = PK11_CipherOp(context, - output_data, - &op_len, - output_len, - input_data, - input_len); - - if (SECSuccess != rv) { - output->clear(); - return false; - } - - unsigned int digest_len; - rv = PK11_DigestFinal(context, - output_data + op_len, - &digest_len, - output_len - op_len); - if (SECSuccess != rv) { - output->clear(); - return false; - } - - output->resize(op_len + digest_len); - return true; -} - -bool Encryptor::CryptCTR(PK11Context* context, - const base::StringPiece& input, - std::string* output) { - if (!counter_.get()) { - LOG(ERROR) << "Counter value not set in CTR mode."; - return false; - } - - size_t output_len = ((input.size() + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * - AES_BLOCK_SIZE; - CHECK_GE(output_len, input.size()); - output->resize(output_len); - uint8_t* output_data = - reinterpret_cast<uint8_t*>(const_cast<char*>(output->data())); - - size_t mask_len; - bool ret = GenerateCounterMask(input.size(), output_data, &mask_len); - if (!ret) - return false; - - CHECK_EQ(mask_len, output_len); - int op_len; - SECStatus rv = PK11_CipherOp(context, - output_data, - &op_len, - output_len, - output_data, - mask_len); - if (SECSuccess != rv) - return false; - CHECK_EQ(static_cast<int>(mask_len), op_len); - - unsigned int digest_len; - rv = PK11_DigestFinal(context, - NULL, - &digest_len, - 0); - if (SECSuccess != rv) - return false; - CHECK(!digest_len); - - // Use |output_data| to mask |input|. - MaskMessage(reinterpret_cast<uint8_t*>(const_cast<char*>(input.data())), - input.length(), output_data, output_data); - output->resize(input.length()); - return true; -} - -} // namespace crypto
diff --git a/crypto/hmac_nss.cc b/crypto/hmac_nss.cc deleted file mode 100644 index 2547860..0000000 --- a/crypto/hmac_nss.cc +++ /dev/null
@@ -1,119 +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/hmac.h" - -#include <nss.h> -#include <pk11pub.h> -#include <stddef.h> - -#include <memory> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" - -namespace crypto { - -struct HMACPlatformData { - CK_MECHANISM_TYPE mechanism_; - ScopedPK11Slot slot_; - ScopedPK11SymKey sym_key_; -}; - -HMAC::HMAC(HashAlgorithm hash_alg) - : hash_alg_(hash_alg), plat_(new HMACPlatformData()) { - // Only SHA-1 and SHA-256 hash algorithms are supported. - switch (hash_alg_) { - case SHA1: - plat_->mechanism_ = CKM_SHA_1_HMAC; - break; - case SHA256: - plat_->mechanism_ = CKM_SHA256_HMAC; - break; - default: - NOTREACHED() << "Unsupported hash algorithm"; - break; - } -} - -HMAC::~HMAC() { -} - -bool HMAC::Init(const unsigned char *key, size_t key_length) { - EnsureNSSInit(); - - if (plat_->slot_.get()) { - // Init must not be called more than twice on the same HMAC object. - NOTREACHED(); - return false; - } - - plat_->slot_.reset(PK11_GetInternalSlot()); - if (!plat_->slot_.get()) { - NOTREACHED(); - return false; - } - - SECItem key_item; - key_item.type = siBuffer; - key_item.data = const_cast<unsigned char*>(key); // NSS API isn't const. - key_item.len = key_length; - - plat_->sym_key_.reset(PK11_ImportSymKey(plat_->slot_.get(), - plat_->mechanism_, - PK11_OriginUnwrap, - CKA_SIGN, - &key_item, - NULL)); - if (!plat_->sym_key_.get()) { - NOTREACHED(); - return false; - } - - return true; -} - -bool HMAC::Sign(const base::StringPiece& data, - unsigned char* digest, - size_t digest_length) const { - if (!plat_->sym_key_.get()) { - // Init has not been called before Sign. - NOTREACHED(); - return false; - } - - SECItem param = { siBuffer, NULL, 0 }; - ScopedPK11Context context(PK11_CreateContextBySymKey(plat_->mechanism_, - CKA_SIGN, - plat_->sym_key_.get(), - ¶m)); - if (!context.get()) { - NOTREACHED(); - return false; - } - - if (PK11_DigestBegin(context.get()) != SECSuccess) { - NOTREACHED(); - return false; - } - - if (PK11_DigestOp(context.get(), - reinterpret_cast<const unsigned char*>(data.data()), - data.length()) != SECSuccess) { - NOTREACHED(); - return false; - } - - unsigned int len = 0; - if (PK11_DigestFinal(context.get(), - digest, &len, digest_length) != SECSuccess) { - NOTREACHED(); - return false; - } - - return true; -} - -} // namespace crypto
diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h index 5a6dc8cf0..0304a8c 100644 --- a/crypto/rsa_private_key.h +++ b/crypto/rsa_private_key.h
@@ -15,15 +15,8 @@ #include "build/build_config.h" #include "crypto/crypto_export.h" -#if defined(USE_OPENSSL) // Forward declaration for openssl/*.h typedef struct evp_pkey_st EVP_PKEY; -#else -// Forward declaration. -typedef struct PK11SlotInfoStr PK11SlotInfo; -typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey; -typedef struct SECKEYPublicKeyStr SECKEYPublicKey; -#endif namespace crypto { @@ -43,23 +36,12 @@ static RSAPrivateKey* CreateFromPrivateKeyInfo( const std::vector<uint8_t>& input); -#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) EVP_PKEY* key() { return key_; } -#else - SECKEYPrivateKey* key() { return key_; } - SECKEYPublicKey* public_key() { return public_key_; } -#endif // Creates a copy of the object. RSAPrivateKey* Copy() const; @@ -74,12 +56,7 @@ // Constructor is private. Use one of the Create*() methods above instead. RSAPrivateKey(); -#if defined(USE_OPENSSL) EVP_PKEY* key_; -#else - SECKEYPrivateKey* key_; - SECKEYPublicKey* public_key_; -#endif DISALLOW_COPY_AND_ASSIGN(RSAPrivateKey); };
diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc deleted file mode 100644 index 2538a723..0000000 --- a/crypto/rsa_private_key_nss.cc +++ /dev/null
@@ -1,633 +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 <cryptohi.h> -#include <keyhi.h> -#include <pk11pub.h> -#include <stdint.h> - -#include <list> -#include <memory> - -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "crypto/nss_key_util.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" - -// Helper for error handling during key import. -#define READ_ASSERT(truth) \ - if (!(truth)) { \ - NOTREACHED(); \ - return false; \ - } - -// TODO(rafaelw): Consider using NSS's ASN.1 encoder. -namespace { - -static bool ReadAttribute(SECKEYPrivateKey* key, - CK_ATTRIBUTE_TYPE type, - std::vector<uint8_t>* output) { - SECItem item; - SECStatus rv; - rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - - output->assign(item.data, item.data + item.len); - SECITEM_FreeItem(&item, PR_FALSE); - return true; -} - -// Used internally by RSAPrivateKey for serializing and deserializing -// PKCS #8 PrivateKeyInfo and PublicKeyInfo. -class PrivateKeyInfoCodec { - public: - // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8. - static const uint8_t kRsaAlgorithmIdentifier[]; - - // ASN.1 tags for some types we use. - static const uint8_t kBitStringTag = 0x03; - static const uint8_t kIntegerTag = 0x02; - static const uint8_t kOctetStringTag = 0x04; - static const uint8_t kSequenceTag = 0x30; - - // |big_endian| here specifies the byte-significance of the integer components - // that will be parsed & serialized (modulus(), etc...) during Import(), - // Export() and ExportPublicKeyInfo() -- not the ASN.1 DER encoding of the - // PrivateKeyInfo/PublicKeyInfo (which is always big-endian). - explicit PrivateKeyInfoCodec(bool big_endian); - - ~PrivateKeyInfoCodec(); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the PrivateKeyInfo structure to |output|. - bool Export(std::vector<uint8_t>* output); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the PublicKeyInfo structure to |output|. - bool ExportPublicKeyInfo(std::vector<uint8_t>* output); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the RSAPublicKey structure to |output|. - bool ExportPublicKey(std::vector<uint8_t>* output); - - // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input| - // and populates the integer components with |big_endian_| byte-significance. - // IMPORTANT NOTE: This is currently *not* security-approved for importing - // keys from unstrusted sources. - bool Import(const std::vector<uint8_t>& input); - - // Accessors to the contents of the integer components of the PrivateKeyInfo - // structure. - std::vector<uint8_t>* modulus() { return &modulus_; } - std::vector<uint8_t>* public_exponent() { return &public_exponent_; } - std::vector<uint8_t>* private_exponent() { return &private_exponent_; } - std::vector<uint8_t>* prime1() { return &prime1_; } - std::vector<uint8_t>* prime2() { return &prime2_; } - std::vector<uint8_t>* exponent1() { return &exponent1_; } - std::vector<uint8_t>* exponent2() { return &exponent2_; } - std::vector<uint8_t>* coefficient() { return &coefficient_; } - - private: - // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_| - // value. - void PrependInteger(const std::vector<uint8_t>& in, std::list<uint8_t>* out); - void PrependInteger(uint8_t* val, int num_bytes, std::list<uint8_t>* data); - - // Prepends the integer stored in |val| - |val + num_bytes| with |big_endian| - // byte-significance into |data| as an ASN.1 integer. - void PrependIntegerImpl(uint8_t* val, - int num_bytes, - std::list<uint8_t>* data, - bool big_endian); - - // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_| - // value. - bool ReadInteger(uint8_t** pos, uint8_t* end, std::vector<uint8_t>* out); - bool ReadIntegerWithExpectedSize(uint8_t** pos, - uint8_t* end, - size_t expected_size, - std::vector<uint8_t>* out); - - // Reads an ASN.1 integer from |pos|, and stores the result into |out| with - // |big_endian| byte-significance. - bool ReadIntegerImpl(uint8_t** pos, - uint8_t* end, - std::vector<uint8_t>* out, - bool big_endian); - - // Prepends the integer stored in |val|, starting a index |start|, for - // |num_bytes| bytes onto |data|. - void PrependBytes(uint8_t* val, - int start, - int num_bytes, - std::list<uint8_t>* data); - - // Helper to prepend an ASN.1 length field. - void PrependLength(size_t size, std::list<uint8_t>* data); - - // Helper to prepend an ASN.1 type header. - void PrependTypeHeaderAndLength(uint8_t type, - uint32_t length, - std::list<uint8_t>* output); - - // Helper to prepend an ASN.1 bit string - void PrependBitString(uint8_t* val, - int num_bytes, - std::list<uint8_t>* output); - - // Read an ASN.1 length field. This also checks that the length does not - // extend beyond |end|. - bool ReadLength(uint8_t** pos, uint8_t* end, uint32_t* result); - - // Read an ASN.1 type header and its length. - bool ReadTypeHeaderAndLength(uint8_t** pos, - uint8_t* end, - uint8_t expected_tag, - uint32_t* length); - - // Read an ASN.1 sequence declaration. This consumes the type header and - // length field, but not the contents of the sequence. - bool ReadSequence(uint8_t** pos, uint8_t* end); - - // Read the RSA AlgorithmIdentifier. - bool ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end); - - // Read one of the two version fields in PrivateKeyInfo. - bool ReadVersion(uint8_t** pos, uint8_t* end); - - // The byte-significance of the stored components (modulus, etc..). - bool big_endian_; - - // Component integers of the PrivateKeyInfo - std::vector<uint8_t> modulus_; - std::vector<uint8_t> public_exponent_; - std::vector<uint8_t> private_exponent_; - std::vector<uint8_t> prime1_; - std::vector<uint8_t> prime2_; - std::vector<uint8_t> exponent1_; - std::vector<uint8_t> exponent2_; - std::vector<uint8_t> coefficient_; - - DISALLOW_COPY_AND_ASSIGN(PrivateKeyInfoCodec); -}; - -const uint8_t PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = { - 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, - 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00}; - -PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian) - : big_endian_(big_endian) {} - -PrivateKeyInfoCodec::~PrivateKeyInfoCodec() {} - -bool PrivateKeyInfoCodec::Export(std::vector<uint8_t>* output) { - std::list<uint8_t> content; - - // Version (always zero) - uint8_t version = 0; - - PrependInteger(coefficient_, &content); - PrependInteger(exponent2_, &content); - PrependInteger(exponent1_, &content); - PrependInteger(prime2_, &content); - PrependInteger(prime1_, &content); - PrependInteger(private_exponent_, &content); - PrependInteger(public_exponent_, &content); - PrependInteger(modulus_, &content); - PrependInteger(&version, 1, &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content); - - // RSA algorithm OID - for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) - content.push_front(kRsaAlgorithmIdentifier[i - 1]); - - PrependInteger(&version, 1, &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everying into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; -} - -bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8_t>* output) { - // Create a sequence with the modulus (n) and public exponent (e). - std::vector<uint8_t> bit_string; - if (!ExportPublicKey(&bit_string)) - return false; - - // Add the sequence as the contents of a bit string. - std::list<uint8_t> content; - PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()), - &content); - - // Add the RSA algorithm OID. - for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) - content.push_front(kRsaAlgorithmIdentifier[i - 1]); - - // Finally, wrap everything in a sequence. - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everything into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; -} - -bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8_t>* output) { - // Create a sequence with the modulus (n) and public exponent (e). - std::list<uint8_t> content; - PrependInteger(&public_exponent_[0], - static_cast<int>(public_exponent_.size()), - &content); - PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everything into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; -} - -bool PrivateKeyInfoCodec::Import(const std::vector<uint8_t>& input) { - if (input.empty()) { - return false; - } - - // Parse the private key info up to the public key values, ignoring - // the subsequent private key values. - uint8_t* src = const_cast<uint8_t*>(&input.front()); - uint8_t* end = src + input.size(); - if (!ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadAlgorithmIdentifier(&src, end) || - !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) || - !ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadInteger(&src, end, &modulus_)) - return false; - - int mod_size = modulus_.size(); - READ_ASSERT(mod_size % 2 == 0); - int primes_size = mod_size / 2; - - if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent_) || - !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient_)) - return false; - - READ_ASSERT(src == end); - - - return true; -} - -void PrivateKeyInfoCodec::PrependInteger(const std::vector<uint8_t>& in, - std::list<uint8_t>* out) { - uint8_t* ptr = const_cast<uint8_t*>(&in.front()); - PrependIntegerImpl(ptr, in.size(), out, big_endian_); -} - -// Helper to prepend an ASN.1 integer. -void PrivateKeyInfoCodec::PrependInteger(uint8_t* val, - int num_bytes, - std::list<uint8_t>* data) { - PrependIntegerImpl(val, num_bytes, data, big_endian_); -} - -void PrivateKeyInfoCodec::PrependIntegerImpl(uint8_t* val, - int num_bytes, - std::list<uint8_t>* data, - bool big_endian) { - // Reverse input if little-endian. - std::vector<uint8_t> tmp; - if (!big_endian) { - tmp.assign(val, val + num_bytes); - std::reverse(tmp.begin(), tmp.end()); - val = &tmp.front(); - } - - // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes - // from the most-significant end of the integer. - int start = 0; - while (start < (num_bytes - 1) && val[start] == 0x00) { - start++; - num_bytes--; - } - PrependBytes(val, start, num_bytes, data); - - // ASN.1 integers are signed. To encode a positive integer whose sign bit - // (the most significant bit) would otherwise be set and make the number - // negative, ASN.1 requires a leading null byte to force the integer to be - // positive. - uint8_t front = data->front(); - if ((front & 0x80) != 0) { - data->push_front(0x00); - num_bytes++; - } - - PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); -} - -bool PrivateKeyInfoCodec::ReadInteger(uint8_t** pos, - uint8_t* end, - std::vector<uint8_t>* out) { - return ReadIntegerImpl(pos, end, out, big_endian_); -} - -bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize( - uint8_t** pos, - uint8_t* end, - size_t expected_size, - std::vector<uint8_t>* out) { - std::vector<uint8_t> temp; - if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian - return false; - - int pad = expected_size - temp.size(); - int index = 0; - if (out->size() == expected_size + 1) { - READ_ASSERT(out->front() == 0x00); - pad++; - index++; - } else { - READ_ASSERT(out->size() <= expected_size); - } - - out->insert(out->end(), pad, 0x00); - out->insert(out->end(), temp.begin(), temp.end()); - - // Reverse output if little-endian. - if (!big_endian_) - std::reverse(out->begin(), out->end()); - return true; -} - -bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8_t** pos, - uint8_t* end, - std::vector<uint8_t>* out, - bool big_endian) { - uint32_t length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length) - return false; - - // The first byte can be zero to force positiveness. We can ignore this. - if (**pos == 0x00) { - ++(*pos); - --length; - } - - if (length) - out->insert(out->end(), *pos, (*pos) + length); - - (*pos) += length; - - // Reverse output if little-endian. - if (!big_endian) - std::reverse(out->begin(), out->end()); - return true; -} - -void PrivateKeyInfoCodec::PrependBytes(uint8_t* val, - int start, - int num_bytes, - std::list<uint8_t>* data) { - while (num_bytes > 0) { - --num_bytes; - data->push_front(val[start + num_bytes]); - } -} - -void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8_t>* data) { - // The high bit is used to indicate whether additional octets are needed to - // represent the length. - if (size < 0x80) { - data->push_front(static_cast<uint8_t>(size)); - } else { - uint8_t num_bytes = 0; - while (size > 0) { - data->push_front(static_cast<uint8_t>(size & 0xFF)); - size >>= 8; - num_bytes++; - } - CHECK_LE(num_bytes, 4); - data->push_front(0x80 | num_bytes); - } -} - -void PrivateKeyInfoCodec::PrependTypeHeaderAndLength( - uint8_t type, - uint32_t length, - std::list<uint8_t>* output) { - PrependLength(length, output); - output->push_front(type); -} - -void PrivateKeyInfoCodec::PrependBitString(uint8_t* val, - int num_bytes, - std::list<uint8_t>* output) { - // Start with the data. - PrependBytes(val, 0, num_bytes, output); - // Zero unused bits. - output->push_front(0); - // Add the length. - PrependLength(num_bytes + 1, output); - // Finally, add the bit string tag. - output->push_front((uint8_t)kBitStringTag); -} - -bool PrivateKeyInfoCodec::ReadLength(uint8_t** pos, - uint8_t* end, - uint32_t* result) { - READ_ASSERT(*pos < end); - int length = 0; - - // If the MSB is not set, the length is just the byte itself. - if (!(**pos & 0x80)) { - length = **pos; - (*pos)++; - } else { - // Otherwise, the lower 7 indicate the length of the length. - int length_of_length = **pos & 0x7F; - READ_ASSERT(length_of_length <= 4); - (*pos)++; - READ_ASSERT(*pos + length_of_length < end); - - length = 0; - for (int i = 0; i < length_of_length; ++i) { - length <<= 8; - length |= **pos; - (*pos)++; - } - } - - READ_ASSERT(*pos + length <= end); - if (result) *result = length; - return true; -} - -bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8_t** pos, - uint8_t* end, - uint8_t expected_tag, - uint32_t* length) { - READ_ASSERT(*pos < end); - READ_ASSERT(**pos == expected_tag); - (*pos)++; - - return ReadLength(pos, end, length); -} - -bool PrivateKeyInfoCodec::ReadSequence(uint8_t** pos, uint8_t* end) { - return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); -} - -bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end) { - READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); - READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, - sizeof(kRsaAlgorithmIdentifier)) == 0); - (*pos) += sizeof(kRsaAlgorithmIdentifier); - return true; -} - -bool PrivateKeyInfoCodec::ReadVersion(uint8_t** pos, uint8_t* end) { - uint32_t length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) - return false; - - // The version should be zero. - for (uint32_t i = 0; i < length; ++i) { - READ_ASSERT(**pos == 0x00); - (*pos)++; - } - - return true; -} - -} // namespace - -namespace crypto { - -RSAPrivateKey::~RSAPrivateKey() { - if (key_) - SECKEY_DestroyPrivateKey(key_); - if (public_key_) - SECKEY_DestroyPublicKey(public_key_); -} - -// static -RSAPrivateKey* RSAPrivateKey::Create(uint16_t num_bits) { - EnsureNSSInit(); - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - 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 -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8_t>& input) { - EnsureNSSInit(); - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - 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 -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; -} - -RSAPrivateKey* RSAPrivateKey::Copy() const { - RSAPrivateKey* copy = new RSAPrivateKey(); - copy->key_ = SECKEY_CopyPrivateKey(key_); - copy->public_key_ = SECKEY_CopyPublicKey(public_key_); - return copy; -} - -bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const { - PrivateKeyInfoCodec private_key_info(true); - - // Manually read the component attributes of the private key and build up - // the PrivateKeyInfo. - if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) || - !ReadAttribute(key_, CKA_PUBLIC_EXPONENT, - private_key_info.public_exponent()) || - !ReadAttribute(key_, CKA_PRIVATE_EXPONENT, - private_key_info.private_exponent()) || - !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) || - !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) || - !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) || - !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) || - !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) { - NOTREACHED(); - return false; - } - - return private_key_info.Export(output); -} - -bool RSAPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const { - ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_)); - if (!der_pubkey.get()) { - NOTREACHED(); - return false; - } - - output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len); - return true; -} - -RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { - EnsureNSSInit(); -} - -} // namespace crypto
diff --git a/crypto/secure_hash_default.cc b/crypto/secure_hash_default.cc deleted file mode 100644 index b33010fd..0000000 --- a/crypto/secure_hash_default.cc +++ /dev/null
@@ -1,60 +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. - -#include "crypto/secure_hash.h" - -#include <stddef.h> - -#include "base/logging.h" -#include "base/pickle.h" -#include "crypto/third_party/nss/chromium-blapi.h" -#include "crypto/third_party/nss/chromium-sha256.h" - -namespace crypto { - -namespace { - -class SecureHashSHA256NSS : public SecureHash { - public: - SecureHashSHA256NSS() { - SHA256_Begin(&ctx_); - } - - SecureHashSHA256NSS(const SecureHashSHA256NSS& other) { - SHA256_Clone(&ctx_, const_cast<SHA256Context*>(&other.ctx_)); - } - - ~SecureHashSHA256NSS() override { memset(&ctx_, 0, sizeof(ctx_)); } - - // SecureHash implementation: - void Update(const void* input, size_t len) override { - SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len); - } - - void Finish(void* output, size_t len) override { - SHA256_End(&ctx_, static_cast<unsigned char*>(output), NULL, - static_cast<unsigned int>(len)); - } - - SecureHash* Clone() const override { return new SecureHashSHA256NSS(*this); } - - size_t GetHashLength() const override { return SHA256_LENGTH; } - - private: - SHA256Context ctx_; -}; - -} // namespace - -SecureHash* SecureHash::Create(Algorithm algorithm) { - switch (algorithm) { - case SHA256: - return new SecureHashSHA256NSS(); - default: - NOTIMPLEMENTED(); - return NULL; - } -} - -} // namespace crypto
diff --git a/crypto/signature_creator.h b/crypto/signature_creator.h index abd1546..98329b8 100644 --- a/crypto/signature_creator.h +++ b/crypto/signature_creator.h
@@ -13,13 +13,8 @@ #include "build/build_config.h" #include "crypto/crypto_export.h" -#if defined(USE_OPENSSL) // Forward declaration for openssl/*.h typedef struct env_md_ctx_st EVP_MD_CTX; -#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) -// Forward declaration. -struct SGNContextStr; -#endif namespace crypto { @@ -61,11 +56,7 @@ // Private constructor. Use the Create() method instead. SignatureCreator(); -#if defined(USE_OPENSSL) EVP_MD_CTX* sign_context_; -#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) - SGNContextStr* sign_context_; -#endif DISALLOW_COPY_AND_ASSIGN(SignatureCreator); };
diff --git a/crypto/signature_creator_nss.cc b/crypto/signature_creator_nss.cc deleted file mode 100644 index 538be93..0000000 --- a/crypto/signature_creator_nss.cc +++ /dev/null
@@ -1,120 +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. - -#include "crypto/signature_creator.h" - -#include <cryptohi.h> -#include <keyhi.h> -#include <stdint.h> -#include <stdlib.h> - -#include <memory> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/rsa_private_key.h" - -namespace crypto { - -namespace { - -SECOidTag ToNSSSigOid(SignatureCreator::HashAlgorithm hash_alg) { - switch (hash_alg) { - case SignatureCreator::SHA1: - return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; - case SignatureCreator::SHA256: - return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; - } - return SEC_OID_UNKNOWN; -} - -SECOidTag ToNSSHashOid(SignatureCreator::HashAlgorithm hash_alg) { - switch (hash_alg) { - case SignatureCreator::SHA1: - return SEC_OID_SHA1; - case SignatureCreator::SHA256: - return SEC_OID_SHA256; - } - return SEC_OID_UNKNOWN; -} - -} // namespace - -SignatureCreator::~SignatureCreator() { - if (sign_context_) { - SGN_DestroyContext(sign_context_, PR_TRUE); - sign_context_ = NULL; - } -} - -// static -SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key, - HashAlgorithm hash_alg) { - std::unique_ptr<SignatureCreator> result(new SignatureCreator); - result->sign_context_ = SGN_NewContext(ToNSSSigOid(hash_alg), key->key()); - if (!result->sign_context_) { - NOTREACHED(); - return NULL; - } - - SECStatus rv = SGN_Begin(result->sign_context_); - if (rv != SECSuccess) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} - -// static -bool SignatureCreator::Sign(RSAPrivateKey* key, - HashAlgorithm hash_alg, - const uint8_t* data, - int data_len, - std::vector<uint8_t>* signature) { - SECItem data_item; - data_item.type = siBuffer; - data_item.data = const_cast<unsigned char*>(data); - data_item.len = data_len; - - SECItem signature_item; - SECStatus rv = SGN_Digest(key->key(), ToNSSHashOid(hash_alg), &signature_item, - &data_item); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - signature->assign(signature_item.data, - signature_item.data + signature_item.len); - SECITEM_FreeItem(&signature_item, PR_FALSE); - return true; -} - -bool SignatureCreator::Update(const uint8_t* data_part, int data_part_len) { - SECStatus rv = SGN_Update(sign_context_, data_part, data_part_len); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - - return true; -} - -bool SignatureCreator::Final(std::vector<uint8_t>* signature) { - SECItem signature_item; - SECStatus rv = SGN_End(sign_context_, &signature_item); - if (rv != SECSuccess) { - return false; - } - signature->assign(signature_item.data, - signature_item.data + signature_item.len); - SECITEM_FreeItem(&signature_item, PR_FALSE); - return true; -} - -SignatureCreator::SignatureCreator() : sign_context_(NULL) { - EnsureNSSInit(); -} - -} // namespace crypto
diff --git a/crypto/signature_verifier.h b/crypto/signature_verifier.h index 5b7369fb..e6b6fc01 100644 --- a/crypto/signature_verifier.h +++ b/crypto/signature_verifier.h
@@ -12,14 +12,8 @@ #include "build/build_config.h" #include "crypto/crypto_export.h" -#if defined(USE_OPENSSL) typedef struct env_md_st EVP_MD; typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; -#else -typedef struct HASHContextStr HASHContext; -typedef struct SECKEYPublicKeyStr SECKEYPublicKey; -typedef struct VFYContextStr VFYContext; -#endif namespace crypto { @@ -96,7 +90,6 @@ bool VerifyFinal(); private: -#if defined(USE_OPENSSL) bool CommonInit(int pkey_type, const EVP_MD* digest, const uint8_t* signature, @@ -104,29 +97,13 @@ const uint8_t* public_key_info, int public_key_info_len, EVP_PKEY_CTX** pkey_ctx); -#else - static SECKEYPublicKey* DecodePublicKeyInfo(const uint8_t* public_key_info, - int public_key_info_len); -#endif void Reset(); std::vector<uint8_t> signature_; -#if defined(USE_OPENSSL) struct VerifyContext; VerifyContext* verify_context_; -#else - // Used for all signature types except RSA-PSS. - VFYContext* vfy_context_; - - // Used for RSA-PSS signatures. - HashAlgorithm hash_alg_; - HashAlgorithm mask_hash_alg_; - unsigned int salt_len_; - SECKEYPublicKey* public_key_; - HASHContext* hash_context_; -#endif }; } // namespace crypto
diff --git a/crypto/signature_verifier_nss.cc b/crypto/signature_verifier_nss.cc deleted file mode 100644 index edbd3f6..0000000 --- a/crypto/signature_verifier_nss.cc +++ /dev/null
@@ -1,213 +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/signature_verifier.h" - -#include <cryptohi.h> -#include <keyhi.h> -#include <pk11pub.h> -#include <secerr.h> -#include <sechash.h> -#include <stdint.h> -#include <stdlib.h> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/third_party/nss/chromium-nss.h" - -namespace crypto { - -namespace { - -HASH_HashType ToNSSHashType(SignatureVerifier::HashAlgorithm hash_alg) { - switch (hash_alg) { - case SignatureVerifier::SHA1: - return HASH_AlgSHA1; - case SignatureVerifier::SHA256: - return HASH_AlgSHA256; - } - return HASH_AlgNULL; -} - -SECOidTag ToNSSSignatureType(SignatureVerifier::SignatureAlgorithm sig_alg) { - switch (sig_alg) { - case SignatureVerifier::RSA_PKCS1_SHA1: - return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; - case SignatureVerifier::RSA_PKCS1_SHA256: - return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; - case SignatureVerifier::ECDSA_SHA256: - return SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; - } - return SEC_OID_UNKNOWN; -} - -SECStatus VerifyRSAPSS_End(SECKEYPublicKey* public_key, - HASHContext* hash_context, - HASH_HashType mask_hash_alg, - unsigned int salt_len, - const unsigned char* signature, - unsigned int signature_len) { - unsigned int hash_len = HASH_ResultLenContext(hash_context); - std::vector<unsigned char> hash(hash_len); - HASH_End(hash_context, &hash[0], &hash_len, hash.size()); - - unsigned int modulus_len = SECKEY_PublicKeyStrength(public_key); - if (signature_len != modulus_len) { - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - return SECFailure; - } - std::vector<unsigned char> enc(signature_len); - SECStatus rv = PK11_PubEncryptRaw(public_key, &enc[0], - const_cast<unsigned char*>(signature), - signature_len, NULL); - if (rv != SECSuccess) { - LOG(WARNING) << "PK11_PubEncryptRaw failed"; - return rv; - } - return emsa_pss_verify(&hash[0], &enc[0], enc.size(), - HASH_GetType(hash_context), mask_hash_alg, - salt_len); -} - -} // namespace - -SignatureVerifier::SignatureVerifier() - : vfy_context_(NULL), - hash_alg_(SHA1), - mask_hash_alg_(SHA1), - salt_len_(0), - public_key_(NULL), - hash_context_(NULL) { - EnsureNSSInit(); -} - -SignatureVerifier::~SignatureVerifier() { - Reset(); -} - -bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm, - const uint8_t* signature, - int signature_len, - const uint8_t* public_key_info, - int public_key_info_len) { - if (vfy_context_ || hash_context_) - return false; - - signature_.assign(signature, signature + signature_len); - - SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info, - public_key_info_len); - if (!public_key) - return false; - - SECItem sig; - sig.type = siBuffer; - sig.data = const_cast<uint8_t*>(signature); - sig.len = signature_len; - vfy_context_ = VFY_CreateContext( - public_key, &sig, ToNSSSignatureType(signature_algorithm), nullptr); - SECKEY_DestroyPublicKey(public_key); // Done with public_key. - if (!vfy_context_) { - // A corrupted RSA signature could be detected without the data, so - // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE - // (-8182). - return false; - } - - if (VFY_Begin(vfy_context_) != SECSuccess) { - NOTREACHED(); - return false; - } - return true; -} - -bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg, - HashAlgorithm mask_hash_alg, - int salt_len, - const uint8_t* signature, - int signature_len, - const uint8_t* public_key_info, - int public_key_info_len) { - if (vfy_context_ || hash_context_) - return false; - - signature_.assign(signature, signature + signature_len); - - SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info, - public_key_info_len); - if (!public_key) - return false; - - public_key_ = public_key; - hash_alg_ = hash_alg; - mask_hash_alg_ = mask_hash_alg; - salt_len_ = salt_len; - hash_context_ = HASH_Create(ToNSSHashType(hash_alg_)); - if (!hash_context_) - return false; - HASH_Begin(hash_context_); - return true; -} - -void SignatureVerifier::VerifyUpdate(const uint8_t* data_part, - int data_part_len) { - if (vfy_context_) { - SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len); - DCHECK_EQ(SECSuccess, rv); - } else { - HASH_Update(hash_context_, data_part, data_part_len); - } -} - -bool SignatureVerifier::VerifyFinal() { - SECStatus rv; - if (vfy_context_) { - rv = VFY_End(vfy_context_); - } else { - rv = VerifyRSAPSS_End(public_key_, hash_context_, - ToNSSHashType(mask_hash_alg_), salt_len_, - signature_.data(), - signature_.size()); - } - Reset(); - - // If signature verification fails, the error code is - // SEC_ERROR_BAD_SIGNATURE (-8182). - return (rv == SECSuccess); -} - -// static -SECKEYPublicKey* SignatureVerifier::DecodePublicKeyInfo( - const uint8_t* public_key_info, - int public_key_info_len) { - CERTSubjectPublicKeyInfo* spki = NULL; - SECItem spki_der; - spki_der.type = siBuffer; - spki_der.data = const_cast<uint8_t*>(public_key_info); - spki_der.len = public_key_info_len; - spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der); - if (!spki) - return NULL; - SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki); - SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki. - return public_key; -} - -void SignatureVerifier::Reset() { - if (vfy_context_) { - VFY_DestroyContext(vfy_context_, PR_TRUE); - vfy_context_ = NULL; - } - if (hash_context_) { - HASH_Destroy(hash_context_); - hash_context_ = NULL; - } - if (public_key_) { - SECKEY_DestroyPublicKey(public_key_); - public_key_ = NULL; - } - signature_.clear(); -} - -} // namespace crypto
diff --git a/crypto/symmetric_key.h b/crypto/symmetric_key.h index 14f74aeb7..b24e2df 100644 --- a/crypto/symmetric_key.h +++ b/crypto/symmetric_key.h
@@ -17,9 +17,6 @@ // 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_CERTS) || \ - (!defined(USE_OPENSSL) && (defined(OS_WIN) || defined(OS_MACOSX))) -#include "crypto/scoped_nss_types.h" #endif namespace crypto { @@ -62,10 +59,8 @@ #if defined(NACL_WIN64) HCRYPTKEY key() const { return key_.get(); } -#elif defined(USE_OPENSSL) +#else const std::string& key() { return key_; } -#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) - PK11SymKey* key() const { return key_.get(); } #endif // Extracts the raw key from the platform specific data. @@ -88,12 +83,9 @@ // TODO(rsleevi): See if KP_EFFECTIVE_KEYLEN is the reason why CryptExportKey // fails with NTE_BAD_KEY/NTE_BAD_LEN std::string raw_key_; -#elif defined(USE_OPENSSL) +#else SymmetricKey() {} std::string key_; -#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) - explicit SymmetricKey(PK11SymKey* key); - ScopedPK11SymKey key_; #endif DISALLOW_COPY_AND_ASSIGN(SymmetricKey);
diff --git a/crypto/symmetric_key_nss.cc b/crypto/symmetric_key_nss.cc deleted file mode 100644 index e3aacc7..0000000 --- a/crypto/symmetric_key_nss.cc +++ /dev/null
@@ -1,151 +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. - -#include "crypto/symmetric_key.h" - -#include <nss.h> -#include <pk11pub.h> -#include <stddef.h> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" - -namespace crypto { - -SymmetricKey::~SymmetricKey() {} - -// static -SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, - size_t key_size_in_bits) { - DCHECK_EQ(AES, algorithm); - - EnsureNSSInit(); - - // Whitelist supported key sizes to avoid accidentaly relying on - // algorithms available in NSS but not BoringSSL and vice - // versa. Note that BoringSSL does not support AES-192. - if (key_size_in_bits != 128 && key_size_in_bits != 256) - return NULL; - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - if (!slot.get()) - return NULL; - - PK11SymKey* sym_key = PK11_KeyGen(slot.get(), CKM_AES_KEY_GEN, NULL, - key_size_in_bits / 8, NULL); - if (!sym_key) - return NULL; - - return new SymmetricKey(sym_key); -} - -// static -SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, - const std::string& password, - const std::string& salt, - size_t iterations, - size_t key_size_in_bits) { - EnsureNSSInit(); - if (salt.empty() || iterations == 0 || key_size_in_bits == 0) - return NULL; - - if (algorithm == AES) { - // Whitelist supported key sizes to avoid accidentaly relying on - // algorithms available in NSS but not BoringSSL and vice - // versa. Note that BoringSSL does not support AES-192. - if (key_size_in_bits != 128 && key_size_in_bits != 256) - return NULL; - } - - SECItem password_item; - password_item.type = siBuffer; - password_item.data = reinterpret_cast<unsigned char*>( - const_cast<char *>(password.data())); - password_item.len = password.size(); - - SECItem salt_item; - salt_item.type = siBuffer; - salt_item.data = reinterpret_cast<unsigned char*>( - const_cast<char *>(salt.data())); - salt_item.len = salt.size(); - - SECOidTag cipher_algorithm = - algorithm == AES ? SEC_OID_AES_256_CBC : SEC_OID_HMAC_SHA1; - ScopedSECAlgorithmID alg_id(PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, - cipher_algorithm, - SEC_OID_HMAC_SHA1, - key_size_in_bits / 8, - iterations, - &salt_item)); - if (!alg_id.get()) - return NULL; - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - if (!slot.get()) - return NULL; - - PK11SymKey* sym_key = PK11_PBEKeyGen(slot.get(), alg_id.get(), &password_item, - PR_FALSE, NULL); - if (!sym_key) - return NULL; - - return new SymmetricKey(sym_key); -} - -// static -SymmetricKey* SymmetricKey::Import(Algorithm algorithm, - const std::string& raw_key) { - EnsureNSSInit(); - - if (algorithm == AES) { - // Whitelist supported key sizes to avoid accidentaly relying on - // algorithms available in NSS but not BoringSSL and vice - // versa. Note that BoringSSL does not support AES-192. - if (raw_key.size() != 128/8 && raw_key.size() != 256/8) - return NULL; - } - - CK_MECHANISM_TYPE cipher = - algorithm == AES ? CKM_AES_CBC : CKM_SHA_1_HMAC; - - SECItem key_item; - key_item.type = siBuffer; - key_item.data = reinterpret_cast<unsigned char*>( - const_cast<char *>(raw_key.data())); - key_item.len = raw_key.size(); - - ScopedPK11Slot slot(PK11_GetInternalSlot()); - if (!slot.get()) - return NULL; - - // The exact value of the |origin| argument doesn't matter to NSS as long as - // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a - // placeholder. - PK11SymKey* sym_key = PK11_ImportSymKey(slot.get(), cipher, PK11_OriginUnwrap, - CKA_ENCRYPT, &key_item, NULL); - if (!sym_key) - return NULL; - - return new SymmetricKey(sym_key); -} - -bool SymmetricKey::GetRawKey(std::string* raw_key) { - SECStatus rv = PK11_ExtractKeyValue(key_.get()); - if (SECSuccess != rv) - return false; - - SECItem* key_item = PK11_GetKeyData(key_.get()); - if (!key_item) - return false; - - raw_key->assign(reinterpret_cast<char*>(key_item->data), key_item->len); - return true; -} - -SymmetricKey::SymmetricKey(PK11SymKey* key) : key_(key) { - DCHECK(key); -} - -} // namespace crypto
diff --git a/crypto/third_party/nss/pk11akey.cc b/crypto/third_party/nss/pk11akey.cc deleted file mode 100644 index 4db582fc6..0000000 --- a/crypto/third_party/nss/pk11akey.cc +++ /dev/null
@@ -1,98 +0,0 @@ - /* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dr Stephen Henson <stephen.henson@gemplus.com> - * Dr Vipul Gupta <vipul.gupta@sun.com>, and - * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "crypto/third_party/nss/chromium-nss.h" - -#include <pk11pub.h> - -#include "base/logging.h" - -// Based on PK11_ImportEncryptedPrivateKeyInfo function in -// mozilla/security/nss/lib/pk11wrap/pk11akey.c. -SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey( - PK11SlotInfo* slot, - SECKEYEncryptedPrivateKeyInfo* epki, - SECItem* password, - SECItem* nickname, - SECItem* public_value, - PRBool permanent, - PRBool sensitive, - SECKEYPrivateKey** private_key, - void* wincx) { - SECItem* crypto_param = NULL; - - CK_ATTRIBUTE_TYPE usage = CKA_SIGN; - - PK11SymKey* key = PK11_PBEKeyGen(slot, - &epki->algorithm, - password, - PR_FALSE, // faulty3DES - wincx); - if (key == NULL) { - DLOG(ERROR) << "PK11_PBEKeyGen: " << PORT_GetError(); - return SECFailure; - } - - CK_MECHANISM_TYPE crypto_mech_type = PK11_GetPBECryptoMechanism( - &epki->algorithm, &crypto_param, password); - if (crypto_mech_type == CKM_INVALID_MECHANISM) { - DLOG(ERROR) << "PK11_GetPBECryptoMechanism: " << PORT_GetError(); - PK11_FreeSymKey(key); - return SECFailure; - } - - crypto_mech_type = PK11_GetPadMechanism(crypto_mech_type); - - *private_key = PK11_UnwrapPrivKey(slot, key, crypto_mech_type, crypto_param, - &epki->encryptedData, nickname, - public_value, permanent, sensitive, CKK_EC, - &usage, 1, wincx); - - if (crypto_param != NULL) - SECITEM_ZfreeItem(crypto_param, PR_TRUE); - - PK11_FreeSymKey(key); - - if (!*private_key) { - DLOG(ERROR) << "PK11_UnwrapPrivKey: " << PORT_GetError(); - return SECFailure; - } - - return SECSuccess; -}
diff --git a/crypto/third_party/nss/rsawrapr.c b/crypto/third_party/nss/rsawrapr.c deleted file mode 100644 index 73e498f9..0000000 --- a/crypto/third_party/nss/rsawrapr.c +++ /dev/null
@@ -1,160 +0,0 @@ -/* - * PKCS#1 encoding and decoding functions. - * This file is believed to contain no code licensed from other parties. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "seccomon.h" -#include "secerr.h" -#include "sechash.h" - -/* Needed for RSA-PSS functions */ -static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - -/* - * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447. - */ -static SECStatus -MGF1(HASH_HashType hashAlg, unsigned char *mask, unsigned int maskLen, - const unsigned char *mgfSeed, unsigned int mgfSeedLen) -{ - unsigned int digestLen; - PRUint32 counter, rounds; - unsigned char *tempHash, *temp; - const SECHashObject *hash; - void *hashContext; - unsigned char C[4]; - - hash = HASH_GetHashObject(hashAlg); - if (hash == NULL) - return SECFailure; - - hashContext = (*hash->create)(); - rounds = (maskLen + hash->length - 1) / hash->length; - for (counter = 0; counter < rounds; counter++) { - C[0] = (unsigned char)((counter >> 24) & 0xff); - C[1] = (unsigned char)((counter >> 16) & 0xff); - C[2] = (unsigned char)((counter >> 8) & 0xff); - C[3] = (unsigned char)(counter & 0xff); - - /* This could be optimized when the clone functions in - * rawhash.c are implemented. */ - (*hash->begin)(hashContext); - (*hash->update)(hashContext, mgfSeed, mgfSeedLen); - (*hash->update)(hashContext, C, sizeof C); - - tempHash = mask + counter * hash->length; - if (counter != (rounds-1)) { - (*hash->end)(hashContext, tempHash, &digestLen, hash->length); - } else { /* we're in the last round and need to cut the hash */ - temp = (unsigned char *)PORT_Alloc(hash->length); - (*hash->end)(hashContext, temp, &digestLen, hash->length); - PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length); - PORT_Free(temp); - } - } - (*hash->destroy)(hashContext, PR_TRUE); - - return SECSuccess; -} - -/* - * Verify a RSA-PSS signature. - * Described in RFC 3447, section 9.1.2. - * We use mHash instead of M as input. - * emBits from the RFC is just modBits - 1, see section 8.1.2. - * We only support MGF1 as the MGF. - * - * NOTE: this code assumes modBits is a multiple of 8. - */ -SECStatus -emsa_pss_verify(const unsigned char *mHash, - const unsigned char *em, unsigned int emLen, - HASH_HashType hashAlg, HASH_HashType maskHashAlg, - unsigned int sLen) -{ - const SECHashObject *hash; - void *hash_context; - unsigned char *db; - unsigned char *H_; /* H' from the RFC */ - unsigned int i, dbMaskLen; - SECStatus rv; - - hash = HASH_GetHashObject(hashAlg); - dbMaskLen = emLen - hash->length - 1; - - /* Step 3 + 4 + 6 */ - if ((emLen < (hash->length + sLen + 2)) || - (em[emLen - 1] != 0xbc) || - ((em[0] & 0x80) != 0)) { - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - return SECFailure; - } - - /* Step 7 */ - db = (unsigned char *)PORT_Alloc(dbMaskLen); - if (db == NULL) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - /* &em[dbMaskLen] points to H, used as mgfSeed */ - MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length); - - /* Step 8 */ - for (i = 0; i < dbMaskLen; i++) { - db[i] ^= em[i]; - } - - /* Step 9 */ - db[0] &= 0x7f; - - /* Step 10 */ - for (i = 0; i < (dbMaskLen - sLen - 1); i++) { - if (db[i] != 0) { - PORT_Free(db); - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - return SECFailure; - } - } - if (db[dbMaskLen - sLen - 1] != 0x01) { - PORT_Free(db); - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - return SECFailure; - } - - /* Step 12 + 13 */ - H_ = (unsigned char *)PORT_Alloc(hash->length); - if (H_ == NULL) { - PORT_Free(db); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - hash_context = (*hash->create)(); - if (hash_context == NULL) { - PORT_Free(db); - PORT_Free(H_); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - (*hash->begin)(hash_context); - (*hash->update)(hash_context, eightZeros, 8); - (*hash->update)(hash_context, mHash, hash->length); - (*hash->update)(hash_context, &db[dbMaskLen - sLen], sLen); - (*hash->end)(hash_context, H_, &i, hash->length); - (*hash->destroy)(hash_context, PR_TRUE); - - PORT_Free(db); - - /* Step 14 */ - if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) { - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - rv = SECFailure; - } else { - rv = SECSuccess; - } - - PORT_Free(H_); - return rv; -}
diff --git a/crypto/third_party/nss/secsign.cc b/crypto/third_party/nss/secsign.cc deleted file mode 100644 index c9816fb0..0000000 --- a/crypto/third_party/nss/secsign.cc +++ /dev/null
@@ -1,132 +0,0 @@ -/* - * Signature stuff. - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "crypto/third_party/nss/chromium-nss.h" - -#include <vector> - -#include <cryptohi.h> -#include <pk11pub.h> -#include <secerr.h> -#include <sechash.h> -#include <stdint.h> - -#include "base/logging.h" -#include "build/build_config.h" - -SECStatus DerSignData(PLArenaPool *arena, - SECItem *result, - SECItem *input, - SECKEYPrivateKey *key, - SECOidTag algo_id) { - if (key->keyType != ecKey) { - return SEC_DerSignData(arena, result, input->data, input->len, key, - algo_id); - } - - // NSS has a private function sec_DecodeSigAlg it uses to figure out the - // correct hash from the algorithm id. - HASH_HashType hash_type; - switch (algo_id) { - case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: - hash_type = HASH_AlgSHA1; - break; -#ifdef SHA224_LENGTH - case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: - hash_type = HASH_AlgSHA224; - break; -#endif - case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: - hash_type = HASH_AlgSHA256; - break; - case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: - hash_type = HASH_AlgSHA384; - break; - case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: - hash_type = HASH_AlgSHA512; - break; - default: - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); - return SECFailure; - } - - // Hash the input. - std::vector<uint8_t> hash_data(HASH_ResultLen(hash_type)); - SECStatus rv = HASH_HashBuf( - hash_type, &hash_data[0], input->data, input->len); - if (rv != SECSuccess) - return rv; - SECItem hash = {siBuffer, &hash_data[0], - static_cast<unsigned int>(hash_data.size())}; - - // Compute signature of hash. - int signature_len = PK11_SignatureLen(key); - std::vector<uint8_t> signature_data(signature_len); - SECItem sig = {siBuffer, &signature_data[0], - static_cast<unsigned int>(signature_len)}; - rv = PK11_Sign(key, &sig, &hash); - if (rv != SECSuccess) - return rv; - - CERTSignedData sd; - PORT_Memset(&sd, 0, sizeof(sd)); - // Fill in tbsCertificate. - sd.data.data = (unsigned char*) input->data; - sd.data.len = input->len; - - // Fill in signatureAlgorithm. - rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algo_id, 0); - if (rv != SECSuccess) - return rv; - - // Fill in signatureValue. - rv = DSAU_EncodeDerSigWithLen(&sd.signature, &sig, sig.len); - if (rv != SECSuccess) - return rv; - sd.signature.len <<= 3; // Convert to bit string. - - // DER encode the signed data object. - void* encode_result = SEC_ASN1EncodeItem( - arena, result, &sd, SEC_ASN1_GET(CERT_SignedDataTemplate)); - - PORT_Free(sd.signature.data); - - return encode_result ? SECSuccess : SECFailure; -}
diff --git a/extensions/renderer/api/display_source/display_source_session.cc b/extensions/renderer/api/display_source/display_source_session.cc index 20b14420..96e5bd5 100644 --- a/extensions/renderer/api/display_source/display_source_session.cc +++ b/extensions/renderer/api/display_source/display_source_session.cc
@@ -14,6 +14,9 @@ : auth_method(api::display_source::AUTHENTICATION_METHOD_NONE) { } +DisplaySourceSessionParams::DisplaySourceSessionParams( + const DisplaySourceSessionParams&) = default; + DisplaySourceSessionParams::~DisplaySourceSessionParams() = default; DisplaySourceSession::DisplaySourceSession()
diff --git a/extensions/renderer/api/display_source/display_source_session.h b/extensions/renderer/api/display_source/display_source_session.h index 922126d9..a16ac5d 100644 --- a/extensions/renderer/api/display_source/display_source_session.h +++ b/extensions/renderer/api/display_source/display_source_session.h
@@ -5,6 +5,8 @@ #ifndef EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_SESSION_H_ #define EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_SESSION_H_ +#include <string> + #include "base/callback.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" @@ -93,6 +95,7 @@ struct DisplaySourceSessionParams { DisplaySourceSessionParams(); + DisplaySourceSessionParams(const DisplaySourceSessionParams&); ~DisplaySourceSessionParams(); int sink_id;
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.cc index 7a3e8f4..cf137df 100644 --- a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.cc +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.cc
@@ -12,6 +12,8 @@ using VideoEncoderCallback = WiFiDisplayVideoEncoder::VideoEncoderCallback; WiFiDisplayVideoEncoder::InitParameters::InitParameters() = default; +WiFiDisplayVideoEncoder::InitParameters::InitParameters(const InitParameters&) = + default; WiFiDisplayVideoEncoder::InitParameters::~InitParameters() = default; WiFiDisplayVideoEncoder::WiFiDisplayVideoEncoder() = default; @@ -32,6 +34,3 @@ } } // namespace extensions - - -
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h index fd093ab..c612089 100644 --- a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h
@@ -56,6 +56,7 @@ struct InitParameters { InitParameters(); + InitParameters(const InitParameters&); ~InitParameters(); gfx::Size frame_size; int frame_rate;
diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js index 13ac7f9..411f9f9d 100644 --- a/extensions/renderer/resources/binding.js +++ b/extensions/renderer/resources/binding.js
@@ -166,6 +166,19 @@ var jsModuleName = type.js_module; logging.CHECK(jsModuleName, 'Custom type ' + type.id + ' has no "js_module" property.'); + // This list contains all types that has a js_module property. It is ugly to + // hard-code them here, but the number of APIs that use js_module has not + // changed since the introduction of js_modules in crbug.com/222156. + // This whitelist serves as an extra line of defence to avoid exposing + // arbitrary extension modules when the |type| definition is poisoned. + var whitelistedModules = [ + 'ChromeDirectSetting', + 'ChromeSetting', + 'ContentSetting', + 'StorageArea', + ]; + logging.CHECK($Array.indexOf(whitelistedModules, jsModuleName) !== -1, + 'Module ' + jsModuleName + ' does not define a custom type.'); var jsModule = require(jsModuleName); logging.CHECK(jsModule, 'No module ' + jsModuleName + ' found for ' + type.id + '.');
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index 088d3373..f1adf42 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -54,8 +54,156 @@ ] } +action("gen_devtools_client_api") { + script = "//headless/lib/browser/client_api_generator.py" + + inputs = [ + "//third_party/WebKit/Source/devtools/protocol.json", + ] + + outputs = [ + "$target_gen_dir/public/domains/accessibility.cc", + "$target_gen_dir/public/domains/accessibility.h", + "$target_gen_dir/public/domains/animation.cc", + "$target_gen_dir/public/domains/animation.h", + "$target_gen_dir/public/domains/application_cache.cc", + "$target_gen_dir/public/domains/application_cache.h", + "$target_gen_dir/public/domains/cache_storage.cc", + "$target_gen_dir/public/domains/cache_storage.h", + "$target_gen_dir/public/domains/console.cc", + "$target_gen_dir/public/domains/console.h", + "$target_gen_dir/public/domains/css.cc", + "$target_gen_dir/public/domains/css.h", + "$target_gen_dir/public/domains/database.cc", + "$target_gen_dir/public/domains/database.h", + "$target_gen_dir/public/domains/debugger.cc", + "$target_gen_dir/public/domains/debugger.h", + "$target_gen_dir/public/domains/device_orientation.cc", + "$target_gen_dir/public/domains/device_orientation.h", + "$target_gen_dir/public/domains/dom_debugger.cc", + "$target_gen_dir/public/domains/dom_debugger.h", + "$target_gen_dir/public/domains/dom.cc", + "$target_gen_dir/public/domains/dom.h", + "$target_gen_dir/public/domains/dom_storage.cc", + "$target_gen_dir/public/domains/dom_storage.h", + "$target_gen_dir/public/domains/emulation.cc", + "$target_gen_dir/public/domains/emulation.h", + "$target_gen_dir/public/domains/heap_profiler.cc", + "$target_gen_dir/public/domains/heap_profiler.h", + "$target_gen_dir/public/domains/indexeddb.cc", + "$target_gen_dir/public/domains/indexeddb.h", + "$target_gen_dir/public/domains/input.cc", + "$target_gen_dir/public/domains/input.h", + "$target_gen_dir/public/domains/inspector.cc", + "$target_gen_dir/public/domains/inspector.h", + "$target_gen_dir/public/domains/io.cc", + "$target_gen_dir/public/domains/io.h", + "$target_gen_dir/public/domains/layer_tree.cc", + "$target_gen_dir/public/domains/layer_tree.h", + "$target_gen_dir/public/domains/memory.cc", + "$target_gen_dir/public/domains/memory.h", + "$target_gen_dir/public/domains/network.cc", + "$target_gen_dir/public/domains/network.h", + "$target_gen_dir/public/domains/page.cc", + "$target_gen_dir/public/domains/page.h", + "$target_gen_dir/public/domains/profiler.cc", + "$target_gen_dir/public/domains/profiler.h", + "$target_gen_dir/public/domains/rendering.cc", + "$target_gen_dir/public/domains/rendering.h", + "$target_gen_dir/public/domains/runtime.cc", + "$target_gen_dir/public/domains/runtime.h", + "$target_gen_dir/public/domains/security.cc", + "$target_gen_dir/public/domains/security.h", + "$target_gen_dir/public/domains/service_worker.cc", + "$target_gen_dir/public/domains/service_worker.h", + "$target_gen_dir/public/domains/tracing.cc", + "$target_gen_dir/public/domains/tracing.h", + "$target_gen_dir/public/domains/type_conversions.h", + "$target_gen_dir/public/domains/types.cc", + "$target_gen_dir/public/domains/types.h", + "$target_gen_dir/public/domains/worker.cc", + "$target_gen_dir/public/domains/worker.h", + ] + + sources = [ + "lib/browser/domain_cc.template", + "lib/browser/domain_h.template", + "lib/browser/type_conversions_h.template", + "lib/browser/types_cc.template", + "lib/browser/types_h.template", + ] + + args = [ + "--protocol", + rebase_path(inputs[0], root_build_dir), + "--output_dir", + rebase_path(target_gen_dir) + "/public/domains", + ] +} + static_library("headless_lib") { sources = [ + "$target_gen_dir/public/domains/accessibility.cc", + "$target_gen_dir/public/domains/accessibility.h", + "$target_gen_dir/public/domains/animation.cc", + "$target_gen_dir/public/domains/animation.h", + "$target_gen_dir/public/domains/application_cache.cc", + "$target_gen_dir/public/domains/application_cache.h", + "$target_gen_dir/public/domains/cache_storage.cc", + "$target_gen_dir/public/domains/cache_storage.h", + "$target_gen_dir/public/domains/console.cc", + "$target_gen_dir/public/domains/console.h", + "$target_gen_dir/public/domains/css.cc", + "$target_gen_dir/public/domains/css.h", + "$target_gen_dir/public/domains/database.cc", + "$target_gen_dir/public/domains/database.h", + "$target_gen_dir/public/domains/debugger.cc", + "$target_gen_dir/public/domains/debugger.h", + "$target_gen_dir/public/domains/device_orientation.cc", + "$target_gen_dir/public/domains/device_orientation.h", + "$target_gen_dir/public/domains/dom.cc", + "$target_gen_dir/public/domains/dom.h", + "$target_gen_dir/public/domains/dom_debugger.cc", + "$target_gen_dir/public/domains/dom_debugger.h", + "$target_gen_dir/public/domains/dom_storage.cc", + "$target_gen_dir/public/domains/dom_storage.h", + "$target_gen_dir/public/domains/emulation.cc", + "$target_gen_dir/public/domains/emulation.h", + "$target_gen_dir/public/domains/heap_profiler.cc", + "$target_gen_dir/public/domains/heap_profiler.h", + "$target_gen_dir/public/domains/indexeddb.cc", + "$target_gen_dir/public/domains/indexeddb.h", + "$target_gen_dir/public/domains/input.cc", + "$target_gen_dir/public/domains/input.h", + "$target_gen_dir/public/domains/inspector.cc", + "$target_gen_dir/public/domains/inspector.h", + "$target_gen_dir/public/domains/io.cc", + "$target_gen_dir/public/domains/io.h", + "$target_gen_dir/public/domains/layer_tree.cc", + "$target_gen_dir/public/domains/layer_tree.h", + "$target_gen_dir/public/domains/memory.cc", + "$target_gen_dir/public/domains/memory.h", + "$target_gen_dir/public/domains/network.cc", + "$target_gen_dir/public/domains/network.h", + "$target_gen_dir/public/domains/page.cc", + "$target_gen_dir/public/domains/page.h", + "$target_gen_dir/public/domains/profiler.cc", + "$target_gen_dir/public/domains/profiler.h", + "$target_gen_dir/public/domains/rendering.cc", + "$target_gen_dir/public/domains/rendering.h", + "$target_gen_dir/public/domains/runtime.cc", + "$target_gen_dir/public/domains/runtime.h", + "$target_gen_dir/public/domains/security.cc", + "$target_gen_dir/public/domains/security.h", + "$target_gen_dir/public/domains/service_worker.cc", + "$target_gen_dir/public/domains/service_worker.h", + "$target_gen_dir/public/domains/tracing.cc", + "$target_gen_dir/public/domains/tracing.h", + "$target_gen_dir/public/domains/type_conversions.h", + "$target_gen_dir/public/domains/types.cc", + "$target_gen_dir/public/domains/types.h", + "$target_gen_dir/public/domains/worker.cc", + "$target_gen_dir/public/domains/worker.h", "lib/browser/headless_browser_context.cc", "lib/browser/headless_browser_context.h", "lib/browser/headless_browser_impl.cc", @@ -66,6 +214,8 @@ "lib/browser/headless_content_browser_client.h", "lib/browser/headless_devtools.cc", "lib/browser/headless_devtools.h", + "lib/browser/headless_devtools_client_impl.cc", + "lib/browser/headless_devtools_client_impl.h", "lib/browser/headless_screen.cc", "lib/browser/headless_screen.h", "lib/browser/headless_url_request_context_getter.cc", @@ -82,14 +232,19 @@ "lib/utility/headless_content_utility_client.h", "public/headless_browser.cc", "public/headless_browser.h", + "public/headless_devtools_client.h", + "public/headless_devtools_host.h", + "public/headless_devtools_target.h", "public/headless_export.h", "public/headless_web_contents.h", + "public/internal/message_dispatcher.h", + "public/internal/value_conversions.h", "public/util/error_reporter.cc", "public/util/error_reporter.h", - "public/util/maybe.h", ] deps = [ + ":gen_devtools_client_api", ":pak", "//base", "//components/devtools_http_handler", @@ -112,6 +267,7 @@ testonly = true deps = [ + ":client_api_generator_tests", ":headless_browsertests", ":headless_unittests", ] @@ -119,8 +275,8 @@ test("headless_unittests") { sources = [ + "public/domains/types_unittest.cc", "public/util/error_reporter_unittest.cc", - "public/util/maybe_unittest.cc", ] deps = [ @@ -131,9 +287,27 @@ ] } +action("client_api_generator_tests") { + _stamp = "$target_gen_dir/client_api_generator_unittests.stamp" + inputs = [ + "lib/browser/client_api_generator.py", + "lib/browser/client_api_generator_unittest.py", + ] + outputs = [ + _stamp, + ] + + script = "lib/browser/client_api_generator_unittest.py" + args = [ + "--stamp", + rebase_path(_stamp, root_build_dir), + ] +} + test("headless_browsertests") { sources = [ "lib/headless_browser_browsertest.cc", + "lib/headless_devtools_client_browsertest.cc", "lib/headless_web_contents_browsertest.cc", "test/headless_browser_test.cc", "test/headless_browser_test.h",
diff --git a/headless/README.md b/headless/README.md index be67643..9e3c7b0 100644 --- a/headless/README.md +++ b/headless/README.md
@@ -55,10 +55,14 @@ - `SetProxyServer` - Configures an HTTP/HTTPS proxy server to be used for accessing the network. -## Client API +## Client/DevTools API The headless client API is used to drive the browser and interact with loaded web pages. Its main classes are: - `HeadlessBrowser` - Represents the global headless browser instance. - `HeadlessWebContents` - Represents a single "tab" within the browser. +- `HeadlessDevToolsClient` - Provides a C++ interface for inspecting and + controlling a tab. The API functions corresponds to [DevTools commands](https://developer.chrome.com/devtools/docs/debugger-protocol). + See the [client API documentation](https://docs.google.com/document/d/1rlqcp8nk-ZQvldNJWdbaMbwfDbJoOXvahPCDoPGOwhQ/edit#) + for more information.
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc index 1031dbd..127c97b 100644 --- a/headless/app/headless_shell.cc +++ b/headless/app/headless_shell.cc
@@ -13,13 +13,18 @@ #include "base/strings/string_number_conversions.h" #include "content/public/common/content_switches.h" #include "headless/app/headless_shell_switches.h" +#include "headless/public/domains/page.h" #include "headless/public/headless_browser.h" +#include "headless/public/headless_devtools_client.h" +#include "headless/public/headless_devtools_target.h" #include "headless/public/headless_web_contents.h" #include "net/base/ip_address.h" #include "ui/gfx/geometry/size.h" using headless::HeadlessBrowser; +using headless::HeadlessDevToolsClient; using headless::HeadlessWebContents; +namespace page = headless::page; namespace { // Address where to listen to incoming DevTools connections. @@ -29,10 +34,14 @@ // A sample application which demonstrates the use of the headless API. class HeadlessShell : public HeadlessWebContents::Observer { public: - HeadlessShell() : browser_(nullptr) {} - ~HeadlessShell() override { - if (web_contents_) - web_contents_->RemoveObserver(this); + HeadlessShell() + : browser_(nullptr), devtools_client_(HeadlessDevToolsClient::Create()) {} + ~HeadlessShell() override {} + + void DevToolsTargetReady() override { + if (!RemoteDebuggingEnabled()) + web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); + // TODO(skyostil): Implement more features to demonstrate the devtools API. } void OnStart(HeadlessBrowser* browser) { @@ -58,9 +67,9 @@ } void ShutdownIfNeeded() { - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - if (!command_line.HasSwitch(switches::kRemoteDebuggingPort)) { + if (!RemoteDebuggingEnabled()) { + web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); + web_contents_->RemoveObserver(this); web_contents_ = nullptr; browser_->Shutdown(); } @@ -71,8 +80,15 @@ ShutdownIfNeeded(); } + bool RemoteDebuggingEnabled() const { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + return command_line.HasSwitch(switches::kRemoteDebuggingPort); + } + private: HeadlessBrowser* browser_; // Not owned. + std::unique_ptr<HeadlessDevToolsClient> devtools_client_; std::unique_ptr<HeadlessWebContents> web_contents_; DISALLOW_COPY_AND_ASSIGN(HeadlessShell);
diff --git a/headless/lib/browser/client_api_generator.py b/headless/lib/browser/client_api_generator.py new file mode 100644 index 0000000..3fcef260 --- /dev/null +++ b/headless/lib/browser/client_api_generator.py
@@ -0,0 +1,372 @@ +# Copyright 2016 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. + +import argparse +import os.path +import sys +import re +try: + import json +except ImportError: + import simplejson as json + +# Path handling for libraries and templates +# Paths have to be normalized because Jinja uses the exact template path to +# determine the hash used in the cache filename, and we need a pre-caching step +# to be concurrency-safe. Use absolute path because __file__ is absolute if +# module is imported, and relative if executed directly. +# If paths differ between pre-caching and individual file compilation, the cache +# is regenerated, which causes a race condition and breaks concurrent build, +# since some compile processes will try to read the partially written cache. +module_path, module_filename = os.path.split(os.path.realpath(__file__)) +third_party_dir = os.path.normpath(os.path.join( + module_path, os.pardir, os.pardir, os.pardir, 'third_party')) +templates_dir = module_path + +# jinja2 is in chromium's third_party directory. +# Insert at 1 so at front to override system libraries, and +# after path[0] == invoking script dir +sys.path.insert(1, third_party_dir) +import jinja2 + + +def ParseArguments(args): + """Parses command line arguments and returns a (json_api, output_dir) tuple. + """ + cmdline_parser = argparse.ArgumentParser() + cmdline_parser.add_argument('--protocol', required=True) + cmdline_parser.add_argument('--output_dir', required=True) + + args = cmdline_parser.parse_args(args) + with open(args.protocol, 'r') as f: + return json.load(f), args.output_dir + + +def ToTitleCase(name): + return name[:1].upper() + name[1:] + + +def DashToCamelCase(word): + return ''.join(ToTitleCase(x) for x in word.split('-')) + + +def CamelCaseToHackerStyle(name): + # Do two passes to insert '_' chars to deal with overlapping matches (e.g., + # 'LoLoLoL'). + name = re.sub(r'([^_])([A-Z][a-z]+?)', r'\1_\2', name) + name = re.sub(r'([^_])([A-Z][a-z]+?)', r'\1_\2', name) + return name.lower() + + +def MangleEnum(value): + # Rename NULL enumeration values to avoid a clash with the actual NULL. + return 'NONE' if value == 'NULL' else value + + +def InitializeJinjaEnv(cache_dir): + jinja_env = jinja2.Environment( + loader=jinja2.FileSystemLoader(templates_dir), + # Bytecode cache is not concurrency-safe unless pre-cached: + # if pre-cached this is read-only, but writing creates a race condition. + bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), + keep_trailing_newline=True, # Newline-terminate generated files. + lstrip_blocks=True, # So we can indent control flow tags. + trim_blocks=True) + jinja_env.filters.update({ + 'to_title_case': ToTitleCase, + 'dash_to_camelcase': DashToCamelCase, + 'camelcase_to_hacker_style': CamelCaseToHackerStyle, + 'mangle_enum': MangleEnum, + }) + jinja_env.add_extension('jinja2.ext.loopcontrols') + return jinja_env + + +def PatchFullQualifiedRefs(json_api): + def PatchFullQualifiedRefsInDomain(json, domain_name): + if isinstance(json, list): + for item in json: + PatchFullQualifiedRefsInDomain(item, domain_name) + + if not isinstance(json, dict): + return + for key in json: + if key != '$ref': + PatchFullQualifiedRefsInDomain(json[key], domain_name) + continue + if not '.' in json['$ref']: + json['$ref'] = domain_name + '.' + json['$ref'] + + for domain in json_api['domains']: + PatchFullQualifiedRefsInDomain(domain, domain['domain']) + + +def CreateUserTypeDefinition(domain, type): + namespace = CamelCaseToHackerStyle(domain['domain']) + return { + 'return_type': 'std::unique_ptr<headless::%s::%s>' % ( + namespace, type['id']), + 'pass_type': 'std::unique_ptr<headless::%s::%s>' % (namespace, type['id']), + 'to_raw_type': '*%s', + 'to_raw_return_type': '%s.get()', + 'to_pass_type': 'std::move(%s)', + 'type': 'std::unique_ptr<headless::%s::%s>' % (namespace, type['id']), + 'raw_type': 'headless::%s::%s' % (namespace, type['id']), + 'raw_pass_type': 'headless::%s::%s*' % (namespace, type['id']), + 'raw_return_type': 'headless::%s::%s*' % (namespace, type['id']), + } + + +def CreateEnumTypeDefinition(domain_name, type): + namespace = CamelCaseToHackerStyle(domain_name) + return { + 'return_type': 'headless::%s::%s' % (namespace, type['id']), + 'pass_type': 'headless::%s::%s' % (namespace, type['id']), + 'to_raw_type': '%s', + 'to_raw_return_type': '%s', + 'to_pass_type': '%s', + 'type': 'headless::%s::%s' % (namespace, type['id']), + 'raw_type': 'headless::%s::%s' % (namespace, type['id']), + 'raw_pass_type': 'headless::%s::%s' % (namespace, type['id']), + 'raw_return_type': 'headless::%s::%s' % (namespace, type['id']), + } + + +def CreateObjectTypeDefinition(): + return { + 'return_type': 'std::unique_ptr<base::DictionaryValue>', + 'pass_type': 'std::unique_ptr<base::DictionaryValue>', + 'to_raw_type': '*%s', + 'to_raw_return_type': '%s.get()', + 'to_pass_type': 'std::move(%s)', + 'type': 'std::unique_ptr<base::DictionaryValue>', + 'raw_type': 'base::DictionaryValue', + 'raw_pass_type': 'base::DictionaryValue*', + 'raw_return_type': 'base::DictionaryValue*', + } + + +def WrapObjectTypeDefinition(type): + id = type.get('id', 'base::Value') + return { + 'return_type': 'std::unique_ptr<%s>' % id, + 'pass_type': 'std::unique_ptr<%s>' % id, + 'to_raw_type': '*%s', + 'to_raw_return_type': '%s.get()', + 'to_pass_type': 'std::move(%s)', + 'type': 'std::unique_ptr<%s>' % id, + 'raw_type': id, + 'raw_pass_type': '%s*' % id, + 'raw_return_type': '%s*' % id, + } + + +def CreateAnyTypeDefinition(): + return { + 'return_type': 'std::unique_ptr<base::Value>', + 'pass_type': 'std::unique_ptr<base::Value>', + 'to_raw_type': '*%s', + 'to_raw_return_type': '%s.get()', + 'to_pass_type': 'std::move(%s)', + 'type': 'std::unique_ptr<base::Value>', + 'raw_type': 'base::Value', + 'raw_pass_type': 'base::Value*', + 'raw_return_type': 'base::Value*', + } + + +def CreateStringTypeDefinition(domain): + return { + 'return_type': 'std::string', + 'pass_type': 'const std::string&', + 'to_pass_type': '%s', + 'to_raw_type': '%s', + 'to_raw_return_type': '%s', + 'type': 'std::string', + 'raw_type': 'std::string', + 'raw_pass_type': 'const std::string&', + 'raw_return_type': 'std::string', + } + + +def CreatePrimitiveTypeDefinition(type): + typedefs = { + 'number': 'double', + 'integer': 'int', + 'boolean': 'bool', + 'string': 'std::string', + } + return { + 'return_type': typedefs[type], + 'pass_type': typedefs[type], + 'to_pass_type': '%s', + 'to_raw_type': '%s', + 'to_raw_return_type': '%s', + 'type': typedefs[type], + 'raw_type': typedefs[type], + 'raw_pass_type': typedefs[type], + 'raw_return_type': typedefs[type], + } + + +type_definitions = {} +type_definitions['number'] = CreatePrimitiveTypeDefinition('number') +type_definitions['integer'] = CreatePrimitiveTypeDefinition('integer') +type_definitions['boolean'] = CreatePrimitiveTypeDefinition('boolean') +type_definitions['string'] = CreatePrimitiveTypeDefinition('string') +type_definitions['object'] = CreateObjectTypeDefinition() +type_definitions['any'] = CreateAnyTypeDefinition() + + +def WrapArrayDefinition(type): + return { + 'return_type': 'std::vector<%s>' % type['type'], + 'pass_type': 'std::vector<%s>' % type['type'], + 'to_raw_type': '%s', + 'to_raw_return_type': '&%s', + 'to_pass_type': 'std::move(%s)', + 'type': 'std::vector<%s>' % type['type'], + 'raw_type': 'std::vector<%s>' % type['type'], + 'raw_pass_type': 'std::vector<%s>*' % type['type'], + 'raw_return_type': 'std::vector<%s>*' % type['type'], + } + + +def CreateTypeDefinitions(json_api): + for domain in json_api['domains']: + if not ('types' in domain): + continue + for type in domain['types']: + if type['type'] == 'object': + if 'properties' in type: + type_definitions[domain['domain'] + '.' + type['id']] = ( + CreateUserTypeDefinition(domain, type)) + else: + type_definitions[domain['domain'] + '.' + type['id']] = ( + CreateObjectTypeDefinition()) + elif type['type'] == 'array': + items_type = type['items']['type'] + type_definitions[domain['domain'] + '.' + type['id']] = ( + WrapArrayDefinition(type_definitions[items_type])) + elif 'enum' in type: + type_definitions[domain['domain'] + '.' + type['id']] = ( + CreateEnumTypeDefinition(domain['domain'], type)) + type['$ref'] = domain['domain'] + '.' + type['id'] + elif type['type'] == 'any': + type_definitions[domain['domain'] + '.' + type['id']] = ( + CreateAnyTypeDefinition()) + else: + type_definitions[domain['domain'] + '.' + type['id']] = ( + CreatePrimitiveTypeDefinition(type['type'])) + + +def TypeDefinition(name): + return type_definitions[name] + + +def ResolveType(property): + if '$ref' in property: + return type_definitions[property['$ref']] + elif property['type'] == 'object': + return WrapObjectTypeDefinition(property) + elif property['type'] == 'array': + return WrapArrayDefinition(ResolveType(property['items'])) + return type_definitions[property['type']] + + +def JoinArrays(dict, keys): + result = [] + for key in keys: + if key in dict: + result += dict[key] + return result + + +def SynthesizeEnumType(domain, owner, type): + type['id'] = ToTitleCase(owner) + ToTitleCase(type['name']) + type_definitions[domain['domain'] + '.' + type['id']] = ( + CreateEnumTypeDefinition(domain['domain'], type)) + type['$ref'] = domain['domain'] + '.' + type['id'] + domain['types'].append(type) + + +def SynthesizeCommandTypes(json_api): + """Generate types for command parameters, return values and enum + properties.""" + for domain in json_api['domains']: + if not 'types' in domain: + domain['types'] = [] + for type in domain['types']: + if type['type'] == 'object': + for property in type.get('properties', []): + if 'enum' in property and not '$ref' in property: + SynthesizeEnumType(domain, type['id'], property) + + for command in domain.get('commands', []): + if 'parameters' in command: + for parameter in command['parameters']: + if 'enum' in parameter and not '$ref' in parameter: + SynthesizeEnumType(domain, command['name'], parameter) + parameters_type = { + 'id': ToTitleCase(command['name']) + 'Params', + 'type': 'object', + 'description': 'Parameters for the %s command.' % ToTitleCase( + command['name']), + 'properties': command['parameters'] + } + domain['types'].append(parameters_type) + if 'returns' in command: + for parameter in command['returns']: + if 'enum' in parameter and not '$ref' in parameter: + SynthesizeEnumType(domain, command['name'], parameter) + result_type = { + 'id': ToTitleCase(command['name']) + 'Result', + 'type': 'object', + 'description': 'Result for the %s command.' % ToTitleCase( + command['name']), + 'properties': command['returns'] + } + domain['types'].append(result_type) + + +def Generate(jinja_env, output_dirname, json_api, class_name, file_types): + template_context = { + 'api': json_api, + 'join_arrays': JoinArrays, + 'resolve_type': ResolveType, + 'type_definition': TypeDefinition, + } + for file_type in file_types: + template = jinja_env.get_template('/%s_%s.template' % ( + class_name, file_type)) + output_file = '%s/%s.%s' % (output_dirname, class_name, file_type) + with open(output_file, 'w') as f: + f.write(template.render(template_context)) + + +def GenerateDomains(jinja_env, output_dirname, json_api, class_name, + file_types): + for file_type in file_types: + template = jinja_env.get_template('/%s_%s.template' % ( + class_name, file_type)) + for domain in json_api['domains']: + template_context = { + 'domain': domain, + 'resolve_type': ResolveType, + } + domain_name = CamelCaseToHackerStyle(domain['domain']) + output_file = '%s/%s.%s' % (output_dirname, domain_name, file_type) + with open(output_file, 'w') as f: + f.write(template.render(template_context)) + + +if __name__ == '__main__': + json_api, output_dirname = ParseArguments(sys.argv[1:]) + jinja_env = InitializeJinjaEnv(output_dirname) + SynthesizeCommandTypes(json_api) + PatchFullQualifiedRefs(json_api) + CreateTypeDefinitions(json_api) + Generate(jinja_env, output_dirname, json_api, 'types', ['cc', 'h']) + Generate(jinja_env, output_dirname, json_api, 'type_conversions', ['h']) + GenerateDomains(jinja_env, output_dirname, json_api, 'domain', ['cc', 'h'])
diff --git a/headless/lib/browser/client_api_generator_unittest.py b/headless/lib/browser/client_api_generator_unittest.py new file mode 100644 index 0000000..f3609d49 --- /dev/null +++ b/headless/lib/browser/client_api_generator_unittest.py
@@ -0,0 +1,386 @@ +# Copyright 2016 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. + +import argparse +import client_api_generator +import shutil +import sys +import tempfile +import unittest + + +class ClientApiGeneratorTest(unittest.TestCase): + + def test_ArgumentParsing(self): + with tempfile.NamedTemporaryFile() as f: + f.write('{"foo": true}') + f.flush() + json_api, output_dir = client_api_generator.ParseArguments([ + '--protocol', f.name, '--output_dir', 'out']) + self.assertEqual({'foo': True}, json_api) + self.assertEqual('out', output_dir) + + def test_ToTitleCase(self): + self.assertEqual(client_api_generator.ToTitleCase('fooBar'), 'FooBar') + + def test_DashToCamelCase(self): + self.assertEqual(client_api_generator.DashToCamelCase('foo-bar'), 'FooBar') + self.assertEqual(client_api_generator.DashToCamelCase('foo-'), 'Foo') + self.assertEqual(client_api_generator.DashToCamelCase('-bar'), 'Bar') + + def test_CamelCaseToHackerStyle(self): + self.assertEqual(client_api_generator.CamelCaseToHackerStyle('FooBar'), + 'foo_bar') + self.assertEqual(client_api_generator.CamelCaseToHackerStyle('LoLoLoL'), + 'lo_lo_lol') + + def test_MangleEnum(self): + self.assertEqual(client_api_generator.MangleEnum('FOO'), 'FOO') + self.assertEqual(client_api_generator.MangleEnum('NULL'), 'NONE') + + def test_PatchFullQualifiedRefs(self): + json_api = { + 'domains': [ + { + 'domain': 'domain0', + '$ref': 'reference', + }, + { + 'domain': 'domain1', + '$ref': 'reference', + 'more': [{'$ref': 'domain0.thing'}], + } + ] + } + expected_json_api = { + 'domains': [ + { + 'domain': 'domain0', + '$ref': 'domain0.reference', + }, + { + 'domain': 'domain1', + '$ref': 'domain1.reference', + 'more': [{'$ref': 'domain0.thing'}], + } + ] + } + client_api_generator.PatchFullQualifiedRefs(json_api) + self.assertDictEqual(json_api, expected_json_api) + + def test_NumberType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'number', + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('double', resolved['raw_type']) + + def test_IntegerType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'integer', + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('int', resolved['raw_type']) + + def test_BooleanType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'boolean', + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('bool', resolved['raw_type']) + + def test_StringType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'string', + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('std::string', resolved['raw_type']) + + def test_ObjectType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'object', + 'properties': [ + {'name': 'p1', 'type': 'number'}, + {'name': 'p2', 'type': 'integer'}, + {'name': 'p3', 'type': 'boolean'}, + {'name': 'p4', 'type': 'string'}, + {'name': 'p5', 'type': 'any'}, + {'name': 'p6', 'type': 'object', '$ref': 'TestType'}, + ], + 'returns': [ + {'name': 'r1', 'type': 'number'}, + {'name': 'r2', 'type': 'integer'}, + {'name': 'r3', 'type': 'boolean'}, + {'name': 'r4', 'type': 'string'}, + {'name': 'r5', 'type': 'any'}, + {'name': 'r6', 'type': 'object', '$ref': 'TestType'}, + ], + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('TestType', resolved['raw_type']) + + def test_AnyType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'any', + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('base::Value', resolved['raw_type']) + + def test_ArrayType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'array', + 'items': {'type': 'integer'} + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('std::vector<int>', resolved['raw_type']) + + def test_EnumType(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'string', + 'enum': ['a', 'b', 'c'] + }, + ] + }, + ] + } + client_api_generator.CreateTypeDefinitions(json_api) + type = json_api['domains'][0]['types'][0] + resolved = client_api_generator.ResolveType(type) + self.assertEqual('headless::domain::TestType', resolved['raw_type']) + + def test_SynthesizeCommandTypes(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'commands': [ + { + 'name': 'TestCommand', + 'parameters': [ + {'name': 'p1', 'type': 'number'}, + {'name': 'p2', 'type': 'integer'}, + {'name': 'p3', 'type': 'boolean'}, + {'name': 'p4', 'type': 'string'}, + {'name': 'p5', 'type': 'any'}, + {'name': 'p6', 'type': 'object', '$ref': 'TestType'}, + ], + 'returns': [ + {'name': 'r1', 'type': 'number'}, + {'name': 'r2', 'type': 'integer'}, + {'name': 'r3', 'type': 'boolean'}, + {'name': 'r4', 'type': 'string'}, + {'name': 'r5', 'type': 'any'}, + {'name': 'r6', 'type': 'object', '$ref': 'TestType'}, + ], + }, + ] + }, + ] + } + expected_types = [ + { + 'type': 'object', + 'id': 'TestCommandParams', + 'description': 'Parameters for the TestCommand command.', + 'properties': [ + {'type': 'number', 'name': 'p1'}, + {'type': 'integer', 'name': 'p2'}, + {'type': 'boolean', 'name': 'p3'}, + {'type': 'string', 'name': 'p4'}, + {'type': 'any', 'name': 'p5'}, + {'type': 'object', 'name': 'p6', '$ref': 'TestType'} + ], + }, + { + 'type': 'object', + 'id': 'TestCommandResult', + 'description': 'Result for the TestCommand command.', + 'properties': [ + {'type': 'number', 'name': 'r1'}, + {'type': 'integer', 'name': 'r2'}, + {'type': 'boolean', 'name': 'r3'}, + {'type': 'string', 'name': 'r4'}, + {'type': 'any', 'name': 'r5'}, + {'type': 'object', 'name': 'r6', '$ref': 'TestType'} + ], + } + ] + client_api_generator.SynthesizeCommandTypes(json_api) + types = json_api['domains'][0]['types'] + self.assertListEqual(types, expected_types) + + def test_Generate(self): + json_api = { + 'domains': [ + { + 'domain': 'domain', + 'types': [ + { + 'id': 'TestType', + 'type': 'object', + 'properties': [ + {'name': 'p1', 'type': 'number'}, + {'name': 'p2', 'type': 'integer'}, + {'name': 'p3', 'type': 'boolean'}, + {'name': 'p4', 'type': 'string'}, + {'name': 'p5', 'type': 'any'}, + {'name': 'p6', 'type': 'object', '$ref': 'domain.TestType'}, + ], + 'returns': [ + {'name': 'r1', 'type': 'number'}, + {'name': 'r2', 'type': 'integer'}, + {'name': 'r3', 'type': 'boolean'}, + {'name': 'r4', 'type': 'string'}, + {'name': 'r5', 'type': 'any'}, + {'name': 'r6', 'type': 'object', '$ref': 'domain.TestType'}, + ], + }, + ] + }, + ] + } + try: + dirname = tempfile.mkdtemp() + jinja_env = client_api_generator.InitializeJinjaEnv(dirname) + client_api_generator.Generate(jinja_env, dirname, json_api, 'types', + ['cc']) + client_api_generator.Generate(jinja_env, dirname, json_api, 'types', + ['h']) + # This is just a smoke test; we don't actually verify the generated output + # here. + finally: + shutil.rmtree(dirname) + + def test_GenerateDomains(self): + json_api = { + 'domains': [ + { + 'domain': 'domain0', + 'types': [ + { + 'id': 'TestType', + 'type': 'object', + }, + ] + }, + { + 'domain': 'domain1', + 'types': [ + { + 'id': 'TestType', + 'type': 'object', + }, + ] + }, + ] + } + try: + dirname = tempfile.mkdtemp() + jinja_env = client_api_generator.InitializeJinjaEnv(dirname) + client_api_generator.GenerateDomains(jinja_env, dirname, json_api, + 'domain', ['cc', 'h']) + # This is just a smoke test; we don't actually verify the generated output + # here. + finally: + shutil.rmtree(dirname) + + +if __name__ == '__main__': + cmdline_parser = argparse.ArgumentParser() + cmdline_parser.add_argument('--stamp') + args = cmdline_parser.parse_args() + unittest.main(verbosity=2, exit=False, argv=sys.argv[:1]) + if args.stamp: + with open(args.stamp, 'a') as f: + pass
diff --git a/headless/lib/browser/domain_cc.template b/headless/lib/browser/domain_cc.template new file mode 100644 index 0000000..9a99bde --- /dev/null +++ b/headless/lib/browser/domain_cc.template
@@ -0,0 +1,86 @@ +// This file is generated + +// Copyright 2016 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 "headless/public/domains/{{domain.domain | camelcase_to_hacker_style}}.h" + +#include "base/bind.h" + +namespace headless { + +namespace {{domain.domain | camelcase_to_hacker_style}} { + +Domain::Domain(internal::MessageDispatcher* dispatcher) : dispatcher_(dispatcher) {} + +Domain::~Domain() {} + {% for command in domain.commands %} + {# Skip redirected commands. #} + {% if "redirect" in command %}{% continue %}{% endif %} + + {% set method_name = command.name | to_title_case %} + {% if "parameters" in command and "returns" in command %} +void Domain::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback) { + dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), base::Bind(&Domain::Handle{{method_name}}Response, callback)); + {% elif "parameters" in command %} +void Domain::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::Callback<void()> callback) { + dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), std::move(callback)); + {% elif "returns" in command %} +void Domain::{{method_name}}(base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback) { + dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", base::Bind(&Domain::Handle{{method_name}}Response, std::move(callback))); + {% else %} +void Domain::{{method_name}}(base::Callback<void()> callback) { + dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", std::move(callback)); + {% endif %} +} + {# Generate convenience methods that take the required parameters directly. #} + {% if not "parameters" in command %}{% continue %}{% endif %} + +void Domain::{{method_name}}({##} + {% for parameter in command.parameters -%} + {% if parameter.get("optional", False) -%} + {% break %} + {% endif %} + {% if not loop.first %}, {% endif %} +{{resolve_type(parameter).pass_type}} {{parameter.name | camelcase_to_hacker_style -}} + {% endfor %} + {% if "parameters" in command and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#} + {% if "returns" in command -%} + base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback{##} + {% else -%} + base::Callback<void()> callback{##} + {% endif %}) { + {# Build the parameters object. #} + std::unique_ptr<{{method_name}}Params> params = {{method_name}}Params::Builder() + {% for parameter in command.parameters -%} + {% if parameter.get("optional", False) -%} + {% break %} + {% endif %} + .Set{{parameter.name | to_title_case}}(std::move({{parameter.name | camelcase_to_hacker_style}})) + {% endfor %} + .Build(); + {# Send the message. #} + {{method_name}}(std::move(params), std::move(callback)); +} + {% endfor %} + +{# Generate response handlers for commands that need them. #} +{% for command in domain.commands %} + {% if not "returns" in command %}{% continue %}{% endif %} + {% set method_name = command.name | to_title_case %} + +// static +void Domain::Handle{{method_name}}Response(base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response) { + if (callback.is_null()) + return; + ErrorReporter errors; + std::unique_ptr<{{method_name}}Result> result = {{method_name}}Result::Parse(response, &errors); + DCHECK(!errors.HasErrors()); + callback.Run(std::move(result)); +} +{% endfor %} + +} // namespace {{domain.domain | camelcase_to_hacker_style}} + +} // namespace headless
diff --git a/headless/lib/browser/domain_h.template b/headless/lib/browser/domain_h.template new file mode 100644 index 0000000..0cd03c3 --- /dev/null +++ b/headless/lib/browser/domain_h.template
@@ -0,0 +1,77 @@ +// This file is generated + +// Copyright (c) 2016 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 HEADLESS_PUBLIC_DOMAINS_{{domain.domain | camelcase_to_hacker_style | upper}}_H_ +#define HEADLESS_PUBLIC_DOMAINS_{{domain.domain | camelcase_to_hacker_style | upper}}_H_ + +#include "base/callback.h" +#include "base/values.h" +#include "headless/public/domains/types.h" +#include "headless/public/headless_export.h" +#include "headless/public/internal/message_dispatcher.h" + +namespace headless { +namespace {{domain.domain | camelcase_to_hacker_style}} { + +{% if domain.description %} +// {{domain.description}} +{% endif %} +class HEADLESS_EXPORT Domain { + public: + Domain(internal::MessageDispatcher* dispatcher); + ~Domain(); + + {# Generate methods for each command. #} + {% for command in domain.commands %} + {# Skip redirected commands. #} + {% if "redirect" in command %}{% continue %}{% endif %} + {% set method_name = command.name | to_title_case %} + {% if command.description %} + // {{ command.description }} + {% endif %} + {% if "parameters" in command and "returns" in command %} + void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::Callback<void(std::unique_ptr<{{method_name}}Result>)>()); + {% elif "parameters" in command %} + void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::Callback<void()> callback = base::Callback<void()>()); + {% elif "returns" in command %} + void {{method_name}}(base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::Callback<void(std::unique_ptr<{{method_name}}Result>)>()); + {% else %} + void {{method_name}}(base::Callback<void()> callback = base::Callback<void()>()); + {% endif %} + {# Generate convenience methods that take the required parameters directly. #} + {% if not "parameters" in command %}{% continue %}{% endif %} + void {{method_name}}({##} + {% for parameter in command.parameters -%} + {% if parameter.get("optional", False) -%} + {% break %} + {% endif %} + {% if not loop.first %}, {% endif %} +{{resolve_type(parameter).pass_type}} {{parameter.name | camelcase_to_hacker_style -}} + {% endfor %} + {% if "parameters" in command and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#} + {% if "returns" in command -%} + base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::Callback<void(std::unique_ptr<{{method_name}}Result>)>(){##} + {% else -%} + base::Callback<void()> callback = base::Callback<void()>(){##} + {% endif %}); + {% endfor %} + private: + {# Generate response handlers for commands that need them. #} + {% for command in domain.commands %} + {% if not "returns" in command %}{% continue %}{% endif %} + {% set method_name = command.name | to_title_case %} + static void Handle{{method_name}}Response(base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response); + {% endfor %} + + internal::MessageDispatcher* dispatcher_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(Domain); +}; + +} // namespace {{domain.domain | camelcase_to_hacker_style}} +} // namespace headless + +#endif // HEADLESS_PUBLIC_DOMAINS_{{domain.domain | camelcase_to_hacker_style | upper}}_H_
diff --git a/headless/lib/browser/headless_devtools_client_impl.cc b/headless/lib/browser/headless_devtools_client_impl.cc new file mode 100644 index 0000000..8ce84533 --- /dev/null +++ b/headless/lib/browser/headless_devtools_client_impl.cc
@@ -0,0 +1,308 @@ +// Copyright 2016 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 "headless/lib/browser/headless_devtools_client_impl.h" + +#include <memory> + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/memory/ptr_util.h" +#include "base/values.h" +#include "content/public/browser/devtools_agent_host.h" + +namespace headless { + +// static +std::unique_ptr<HeadlessDevToolsClient> HeadlessDevToolsClient::Create() { + return base::WrapUnique(new HeadlessDevToolsClientImpl()); +} + +// static +HeadlessDevToolsClientImpl* HeadlessDevToolsClientImpl::From( + HeadlessDevToolsClient* client) { + // This downcast is safe because there is only one implementation of + // HeadlessDevToolsClient. + return static_cast<HeadlessDevToolsClientImpl*>(client); +} + +HeadlessDevToolsClientImpl::HeadlessDevToolsClientImpl() + : agent_host_(nullptr), + next_message_id_(0), + accessibility_domain_(this), + animation_domain_(this), + application_cache_domain_(this), + cache_storage_domain_(this), + console_domain_(this), + css_domain_(this), + database_domain_(this), + debugger_domain_(this), + device_orientation_domain_(this), + dom_debugger_domain_(this), + dom_domain_(this), + dom_storage_domain_(this), + emulation_domain_(this), + heap_profiler_domain_(this), + indexeddb_domain_(this), + input_domain_(this), + inspector_domain_(this), + io_domain_(this), + layer_tree_domain_(this), + memory_domain_(this), + network_domain_(this), + page_domain_(this), + profiler_domain_(this), + rendering_domain_(this), + runtime_domain_(this), + security_domain_(this), + service_worker_domain_(this), + tracing_domain_(this), + worker_domain_(this) {} + +HeadlessDevToolsClientImpl::~HeadlessDevToolsClientImpl() {} + +void HeadlessDevToolsClientImpl::AttachToHost( + content::DevToolsAgentHost* agent_host) { + DCHECK(!agent_host_); + agent_host_ = agent_host; + agent_host_->AttachClient(this); +} + +void HeadlessDevToolsClientImpl::DetachFromHost( + content::DevToolsAgentHost* agent_host) { + DCHECK_EQ(agent_host_, agent_host); + agent_host_->DetachClient(); + agent_host_ = nullptr; + pending_messages_.clear(); +} + +void HeadlessDevToolsClientImpl::DispatchProtocolMessage( + content::DevToolsAgentHost* agent_host, + const std::string& json_message) { + DCHECK_EQ(agent_host_, agent_host); + std::unique_ptr<base::Value> message = + base::JSONReader::Read(json_message, base::JSON_PARSE_RFC); + base::DictionaryValue* message_dict; + if (!message || !message->GetAsDictionary(&message_dict)) { + NOTREACHED() << "Badly formed reply"; + return; + } + int id = 0; + DCHECK(message_dict->GetInteger("id", &id)); + auto it = pending_messages_.find(id); + if (it == pending_messages_.end()) { + NOTREACHED() << "Unexpected reply"; + return; + } + base::DictionaryValue* result_dict; + if (message_dict->GetDictionary("result", &result_dict)) { + it->second.callback_with_result.Run(*result_dict); + } else { + it->second.callback.Run(); + } + pending_messages_.erase(it); +} + +void HeadlessDevToolsClientImpl::AgentHostClosed( + content::DevToolsAgentHost* agent_host, + bool replaced_with_another_client) { + DCHECK_EQ(agent_host_, agent_host); + agent_host = nullptr; + pending_messages_.clear(); +} + +accessibility::Domain* HeadlessDevToolsClientImpl::GetAccessibility() { + return &accessibility_domain_; +} + +animation::Domain* HeadlessDevToolsClientImpl::GetAnimation() { + return &animation_domain_; +} + +application_cache::Domain* HeadlessDevToolsClientImpl::GetApplicationCache() { + return &application_cache_domain_; +} + +cache_storage::Domain* HeadlessDevToolsClientImpl::GetCacheStorage() { + return &cache_storage_domain_; +} + +console::Domain* HeadlessDevToolsClientImpl::GetConsole() { + return &console_domain_; +} + +css::Domain* HeadlessDevToolsClientImpl::GetCSS() { + return &css_domain_; +} + +database::Domain* HeadlessDevToolsClientImpl::GetDatabase() { + return &database_domain_; +} + +debugger::Domain* HeadlessDevToolsClientImpl::GetDebugger() { + return &debugger_domain_; +} + +device_orientation::Domain* HeadlessDevToolsClientImpl::GetDeviceOrientation() { + return &device_orientation_domain_; +} + +dom_debugger::Domain* HeadlessDevToolsClientImpl::GetDOMDebugger() { + return &dom_debugger_domain_; +} + +dom::Domain* HeadlessDevToolsClientImpl::GetDOM() { + return &dom_domain_; +} + +dom_storage::Domain* HeadlessDevToolsClientImpl::GetDOMStorage() { + return &dom_storage_domain_; +} + +emulation::Domain* HeadlessDevToolsClientImpl::GetEmulation() { + return &emulation_domain_; +} + +heap_profiler::Domain* HeadlessDevToolsClientImpl::GetHeapProfiler() { + return &heap_profiler_domain_; +} + +indexeddb::Domain* HeadlessDevToolsClientImpl::GetIndexedDB() { + return &indexeddb_domain_; +} + +input::Domain* HeadlessDevToolsClientImpl::GetInput() { + return &input_domain_; +} + +inspector::Domain* HeadlessDevToolsClientImpl::GetInspector() { + return &inspector_domain_; +} + +io::Domain* HeadlessDevToolsClientImpl::GetIO() { + return &io_domain_; +} + +layer_tree::Domain* HeadlessDevToolsClientImpl::GetLayerTree() { + return &layer_tree_domain_; +} + +memory::Domain* HeadlessDevToolsClientImpl::GetMemory() { + return &memory_domain_; +} + +network::Domain* HeadlessDevToolsClientImpl::GetNetwork() { + return &network_domain_; +} + +page::Domain* HeadlessDevToolsClientImpl::GetPage() { + return &page_domain_; +} + +profiler::Domain* HeadlessDevToolsClientImpl::GetProfiler() { + return &profiler_domain_; +} + +rendering::Domain* HeadlessDevToolsClientImpl::GetRendering() { + return &rendering_domain_; +} + +runtime::Domain* HeadlessDevToolsClientImpl::GetRuntime() { + return &runtime_domain_; +} + +security::Domain* HeadlessDevToolsClientImpl::GetSecurity() { + return &security_domain_; +} + +service_worker::Domain* HeadlessDevToolsClientImpl::GetServiceWorker() { + return &service_worker_domain_; +} + +tracing::Domain* HeadlessDevToolsClientImpl::GetTracing() { + return &tracing_domain_; +} + +worker::Domain* HeadlessDevToolsClientImpl::GetWorker() { + return &worker_domain_; +} + +template <typename CallbackType> +void HeadlessDevToolsClientImpl::FinalizeAndSendMessage( + base::DictionaryValue* message, + CallbackType callback) { + DCHECK(agent_host_); + int id = next_message_id_++; + message->SetInteger("id", id); + std::string json_message; + base::JSONWriter::Write(*message, &json_message); + pending_messages_[id] = PendingMessage(callback); + agent_host_->DispatchProtocolMessage(json_message); +} + +template <typename CallbackType> +void HeadlessDevToolsClientImpl::SendMessageWithParams( + const char* method, + std::unique_ptr<base::Value> params, + CallbackType callback) { + base::DictionaryValue message; + message.SetString("method", method); + message.Set("params", std::move(params)); + FinalizeAndSendMessage(&message, std::move(callback)); +} + +template <typename CallbackType> +void HeadlessDevToolsClientImpl::SendMessageWithoutParams( + const char* method, + CallbackType callback) { + base::DictionaryValue message; + message.SetString("method", method); + FinalizeAndSendMessage(&message, std::move(callback)); +} + +void HeadlessDevToolsClientImpl::SendMessage( + const char* method, + std::unique_ptr<base::Value> params, + base::Callback<void(const base::Value&)> callback) { + SendMessageWithParams(method, std::move(params), std::move(callback)); +} + +void HeadlessDevToolsClientImpl::SendMessage( + const char* method, + std::unique_ptr<base::Value> params, + base::Callback<void()> callback) { + SendMessageWithParams(method, std::move(params), std::move(callback)); +} + +void HeadlessDevToolsClientImpl::SendMessage( + const char* method, + base::Callback<void(const base::Value&)> callback) { + SendMessageWithoutParams(method, std::move(callback)); +} + +void HeadlessDevToolsClientImpl::SendMessage(const char* method, + base::Callback<void()> callback) { + SendMessageWithoutParams(method, std::move(callback)); +} + +HeadlessDevToolsClientImpl::PendingMessage::PendingMessage() {} + +HeadlessDevToolsClientImpl::PendingMessage::PendingMessage( + PendingMessage&& other) = default; + +HeadlessDevToolsClientImpl::PendingMessage::PendingMessage( + base::Callback<void()> callback) + : callback(callback) {} + +HeadlessDevToolsClientImpl::PendingMessage::PendingMessage( + base::Callback<void(const base::Value&)> callback) + : callback_with_result(callback) {} + +HeadlessDevToolsClientImpl::PendingMessage::~PendingMessage() {} + +HeadlessDevToolsClientImpl::PendingMessage& +HeadlessDevToolsClientImpl::PendingMessage::operator=(PendingMessage&& other) = + default; + +} // namespace headless
diff --git a/headless/lib/browser/headless_devtools_client_impl.h b/headless/lib/browser/headless_devtools_client_impl.h new file mode 100644 index 0000000..fb5442c --- /dev/null +++ b/headless/lib/browser/headless_devtools_client_impl.h
@@ -0,0 +1,183 @@ +// Copyright 2016 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 HEADLESS_LIB_BROWSER_HEADLESS_DEVTOOLS_CLIENT_IMPL_H_ +#define HEADLESS_LIB_BROWSER_HEADLESS_DEVTOOLS_CLIENT_IMPL_H_ + +#include <unordered_map> + +#include "content/public/browser/devtools_agent_host_client.h" +#include "headless/public/domains/accessibility.h" +#include "headless/public/domains/animation.h" +#include "headless/public/domains/application_cache.h" +#include "headless/public/domains/cache_storage.h" +#include "headless/public/domains/console.h" +#include "headless/public/domains/css.h" +#include "headless/public/domains/database.h" +#include "headless/public/domains/debugger.h" +#include "headless/public/domains/device_orientation.h" +#include "headless/public/domains/dom.h" +#include "headless/public/domains/dom_debugger.h" +#include "headless/public/domains/dom_storage.h" +#include "headless/public/domains/emulation.h" +#include "headless/public/domains/heap_profiler.h" +#include "headless/public/domains/indexeddb.h" +#include "headless/public/domains/input.h" +#include "headless/public/domains/inspector.h" +#include "headless/public/domains/io.h" +#include "headless/public/domains/layer_tree.h" +#include "headless/public/domains/memory.h" +#include "headless/public/domains/network.h" +#include "headless/public/domains/page.h" +#include "headless/public/domains/profiler.h" +#include "headless/public/domains/rendering.h" +#include "headless/public/domains/runtime.h" +#include "headless/public/domains/security.h" +#include "headless/public/domains/service_worker.h" +#include "headless/public/domains/tracing.h" +#include "headless/public/domains/worker.h" +#include "headless/public/headless_devtools_client.h" +#include "headless/public/internal/message_dispatcher.h" + +namespace base { +class DictionaryValue; +} + +namespace content { +class DevToolsAgentHost; +} + +namespace headless { + +class HeadlessDevToolsClientImpl : public HeadlessDevToolsClient, + public content::DevToolsAgentHostClient, + public internal::MessageDispatcher { + public: + HeadlessDevToolsClientImpl(); + ~HeadlessDevToolsClientImpl() override; + + static HeadlessDevToolsClientImpl* From(HeadlessDevToolsClient* client); + + // HeadlessDevToolsClient implementation: + accessibility::Domain* GetAccessibility() override; + animation::Domain* GetAnimation() override; + application_cache::Domain* GetApplicationCache() override; + cache_storage::Domain* GetCacheStorage() override; + console::Domain* GetConsole() override; + css::Domain* GetCSS() override; + database::Domain* GetDatabase() override; + debugger::Domain* GetDebugger() override; + device_orientation::Domain* GetDeviceOrientation() override; + dom::Domain* GetDOM() override; + dom_debugger::Domain* GetDOMDebugger() override; + dom_storage::Domain* GetDOMStorage() override; + emulation::Domain* GetEmulation() override; + heap_profiler::Domain* GetHeapProfiler() override; + indexeddb::Domain* GetIndexedDB() override; + input::Domain* GetInput() override; + inspector::Domain* GetInspector() override; + io::Domain* GetIO() override; + layer_tree::Domain* GetLayerTree() override; + memory::Domain* GetMemory() override; + network::Domain* GetNetwork() override; + page::Domain* GetPage() override; + profiler::Domain* GetProfiler() override; + rendering::Domain* GetRendering() override; + runtime::Domain* GetRuntime() override; + security::Domain* GetSecurity() override; + service_worker::Domain* GetServiceWorker() override; + tracing::Domain* GetTracing() override; + worker::Domain* GetWorker() override; + + // content::DevToolstAgentHostClient implementation: + void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host, + const std::string& json_message) override; + void AgentHostClosed(content::DevToolsAgentHost* agent_host, + bool replaced_with_another_client) override; + + // internal::MessageDispatcher implementation: + void SendMessage(const char* method, + std::unique_ptr<base::Value> params, + base::Callback<void(const base::Value&)> callback) override; + void SendMessage(const char* method, + std::unique_ptr<base::Value> params, + base::Callback<void()> callback) override; + void SendMessage(const char* method, + base::Callback<void(const base::Value&)> callback) override; + void SendMessage(const char* method, + base::Callback<void()> callback) override; + + void AttachToHost(content::DevToolsAgentHost* agent_host); + void DetachFromHost(content::DevToolsAgentHost* agent_host); + + private: + // Represents a message for which we are still waiting for a reply. Contains + // a callback with or without a result parameter depending on the message that + // is pending. + struct PendingMessage { + PendingMessage(); + PendingMessage(PendingMessage&& other); + explicit PendingMessage(base::Callback<void()> callback); + explicit PendingMessage(base::Callback<void(const base::Value&)> callback); + ~PendingMessage(); + + PendingMessage& operator=(PendingMessage&& other); + + // TODO(skyostil): Use a class union once allowed. + base::Callback<void()> callback; + base::Callback<void(const base::Value&)> callback_with_result; + }; + + template <typename CallbackType> + void FinalizeAndSendMessage(base::DictionaryValue* message, + CallbackType callback); + + template <typename CallbackType> + void SendMessageWithParams(const char* method, + std::unique_ptr<base::Value> params, + CallbackType callback); + + template <typename CallbackType> + void SendMessageWithoutParams(const char* method, CallbackType callback); + + content::DevToolsAgentHost* agent_host_; // Not owned. + int next_message_id_; + std::unordered_map<int, PendingMessage> pending_messages_; + + accessibility::Domain accessibility_domain_; + animation::Domain animation_domain_; + application_cache::Domain application_cache_domain_; + cache_storage::Domain cache_storage_domain_; + console::Domain console_domain_; + css::Domain css_domain_; + database::Domain database_domain_; + debugger::Domain debugger_domain_; + device_orientation::Domain device_orientation_domain_; + dom_debugger::Domain dom_debugger_domain_; + dom::Domain dom_domain_; + dom_storage::Domain dom_storage_domain_; + emulation::Domain emulation_domain_; + heap_profiler::Domain heap_profiler_domain_; + indexeddb::Domain indexeddb_domain_; + input::Domain input_domain_; + inspector::Domain inspector_domain_; + io::Domain io_domain_; + layer_tree::Domain layer_tree_domain_; + memory::Domain memory_domain_; + network::Domain network_domain_; + page::Domain page_domain_; + profiler::Domain profiler_domain_; + rendering::Domain rendering_domain_; + runtime::Domain runtime_domain_; + security::Domain security_domain_; + service_worker::Domain service_worker_domain_; + tracing::Domain tracing_domain_; + worker::Domain worker_domain_; + + DISALLOW_COPY_AND_ASSIGN(HeadlessDevToolsClientImpl); +}; + +} // namespace headless + +#endif // HEADLESS_LIB_BROWSER_HEADLESS_DEVTOOLS_CLIENT_IMPL_H_
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc index f58dfe0..94eae96 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -8,6 +8,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" #include "base/trace_event/trace_event.h" +#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -19,6 +20,7 @@ #include "content/public/common/bindings_policy.h" #include "content/public/common/service_registry.h" #include "content/public/renderer/render_frame.h" +#include "headless/lib/browser/headless_devtools_client_impl.h" #include "ui/aura/window.h" namespace headless { @@ -31,7 +33,10 @@ ~WebContentsObserverAdapter() override {} - void RenderViewReady() override { observer_->WebContentsReady(); } + void RenderViewReady() override { + DCHECK(web_contents()->GetMainFrame()->IsRenderFrameLive()); + observer_->DevToolsTargetReady(); + } void DocumentOnLoadCompletedInMainFrame() override { observer_->DocumentOnLoadCompletedInMainFrame(); @@ -107,6 +112,21 @@ observer_map_.erase(it); } +HeadlessDevToolsTarget* HeadlessWebContentsImpl::GetDevToolsTarget() { + return web_contents()->GetMainFrame()->IsRenderFrameLive() ? this : nullptr; +} + +void HeadlessWebContentsImpl::AttachClient(HeadlessDevToolsClient* client) { + if (!agent_host_) + agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(web_contents()); + HeadlessDevToolsClientImpl::From(client)->AttachToHost(agent_host_.get()); +} + +void HeadlessWebContentsImpl::DetachClient(HeadlessDevToolsClient* client) { + DCHECK(agent_host_); + HeadlessDevToolsClientImpl::From(client)->DetachFromHost(agent_host_.get()); +} + content::WebContents* HeadlessWebContentsImpl::web_contents() const { return web_contents_.get(); }
diff --git a/headless/lib/browser/headless_web_contents_impl.h b/headless/lib/browser/headless_web_contents_impl.h index e1cdc2d1..c56c50ee3 100644 --- a/headless/lib/browser/headless_web_contents_impl.h +++ b/headless/lib/browser/headless_web_contents_impl.h
@@ -5,6 +5,7 @@ #ifndef HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_ #define HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_ +#include "headless/public/headless_devtools_target.h" #include "headless/public/headless_web_contents.h" #include <memory> @@ -15,8 +16,9 @@ } namespace content { -class WebContents; class BrowserContext; +class DevToolsAgentHost; +class WebContents; } namespace gfx { @@ -24,9 +26,11 @@ } namespace headless { +class HeadlessDevToolsHostImpl; class WebContentsObserverAdapter; -class HeadlessWebContentsImpl : public HeadlessWebContents { +class HeadlessWebContentsImpl : public HeadlessWebContents, + public HeadlessDevToolsTarget { public: HeadlessWebContentsImpl(content::BrowserContext* context, aura::Window* parent_window, @@ -36,6 +40,11 @@ // HeadlessWebContents implementation: void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; + HeadlessDevToolsTarget* GetDevToolsTarget() override; + + // HeadlessDevToolsTarget implementation: + void AttachClient(HeadlessDevToolsClient* client) override; + void DetachClient(HeadlessDevToolsClient* client) override; content::WebContents* web_contents() const; bool OpenURL(const GURL& url); @@ -44,6 +53,7 @@ class Delegate; std::unique_ptr<Delegate> web_contents_delegate_; std::unique_ptr<content::WebContents> web_contents_; + scoped_refptr<content::DevToolsAgentHost> agent_host_; using ObserverMap = std::unordered_map<HeadlessWebContents::Observer*,
diff --git a/headless/lib/browser/type_conversions_h.template b/headless/lib/browser/type_conversions_h.template new file mode 100644 index 0000000..286b0e5 --- /dev/null +++ b/headless/lib/browser/type_conversions_h.template
@@ -0,0 +1,77 @@ +// This file is generated + +// Copyright 2016 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 HEADLESS_PUBLIC_DOMAINS_TYPE_CONVERSIONS_H_ +#define HEADLESS_PUBLIC_DOMAINS_TYPE_CONVERSIONS_H_ + +#include "headless/public/domains/types.h" +#include "headless/public/internal/value_conversions.h" + +namespace headless { +namespace internal { + +{% for domain in api.domains %} + {% for type in domain.types %} + {% set namespace = domain.domain | camelcase_to_hacker_style %} + {% if "enum" in type %} +template <> +struct FromValue<{{namespace}}::{{type.id}}> { + static {{namespace}}::{{type.id}} Parse(const base::Value& value, ErrorReporter* errors) { + {% set default = namespace + '::' + type.id + '::' + type.enum[0] | dash_to_camelcase | camelcase_to_hacker_style | upper | mangle_enum %} + std::string string_value; + if (!value.GetAsString(&string_value)) { + errors->AddError("string enum value expected"); + {# Return an arbitrary enum member -- the caller will just ignore it. #} + return {{default}}; + } + {% for literal in type.enum %} + if (string_value == "{{literal}}") + return {{namespace}}::{{type.id}}::{{literal | dash_to_camelcase | camelcase_to_hacker_style | upper | mangle_enum}}; + {% endfor %} + errors->AddError("invalid enum value"); + return {{default}}; + } +}; + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const {{namespace}}::{{type.id}}& value, T*) { + switch (value) { + {% for literal in type.enum %} + case {{namespace}}::{{type.id}}::{{literal | dash_to_camelcase | camelcase_to_hacker_style | upper | mangle_enum}}: + return base::WrapUnique(new base::StringValue("{{literal}}")); + {% endfor %} + }; + NOTREACHED(); + return nullptr; +} + {% continue %} + {% endif %} + + {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %} +template <> +struct FromValue<{{namespace}}::{{type.id}}> { + static std::unique_ptr<{{namespace}}::{{type.id}}> Parse(const base::Value& value, ErrorReporter* errors) { + return {{namespace}}::{{type.id}}::Parse(value, errors); + } +}; + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const {{namespace}}::{{type.id}}& value, T*) { + return value.Serialize(); +} + + {% endfor %} +{% endfor %} + +template <typename T> +std::unique_ptr<base::Value> ToValue(const T& value) { + return ToValueImpl(value, static_cast<T*>(nullptr)); +} + +} // namespace internal +} // namespace headless + +#endif // HEADLESS_PUBLIC_DOMAINS_TYPE_CONVERSIONS_H_
diff --git a/headless/lib/browser/types_cc.template b/headless/lib/browser/types_cc.template new file mode 100644 index 0000000..5be72cf --- /dev/null +++ b/headless/lib/browser/types_cc.template
@@ -0,0 +1,130 @@ +// This file is generated + +// Copyright 2016 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 "headless/public/domains/types.h" + +#include "base/memory/ptr_util.h" +#include "headless/public/domains/type_conversions.h" + +namespace headless { + +// ------------- Enum values from types. +{% for domain in api.domains %} + {% continue %} + +namespace internal { + + {% for type in domain.types %} +// {{type}} + {% if type.type == "array" %} +template <> +struct FromValue<{{resolve_type(type).raw_type}}> { + static {{resolve_type(type).raw_type}} Parse(const base::Value& value, ErrorReporter* errors) { + {{resolve_type(type).raw_type}} result; + const base::ListValue* list; + if (!value.GetAsList(&list)) { + errors->AddError("list value expected"); + return result; + } + errors->Push(); + for (const auto& item : *list) + result.push_back(FromValue<{{resolve_type(type).raw_type}}::value_type>::Parse(*item, errors)); + errors->Pop(); + return result; + } +}; + + {% continue %} + {% endif %} +#} + {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %} + {% set namespace = domain.domain | camelcase_to_hacker_style %} +template <> +struct FromValue<{{namespace}}::{{type.id}}> { + static std::unique_ptr<{{namespace}}::{{type.id}}> Parse(const base::Value& value, ErrorReporter* errors) { + return {{namespace}}::{{type.id}}::Parse(value, errors); + } +}; + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const {{namespace}}::{{type.id}}& value, T*) { + return value.Serialize(); +} + + {% endfor %} +} // namespace internal +{% endfor %} + +{% for domain in api.domains %} + +namespace {{domain.domain | camelcase_to_hacker_style}} { + {% for type in domain.types %} + {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %} + +std::unique_ptr<{{type.id}}> {{type.id}}::Parse(const base::Value& value, ErrorReporter* errors) { + errors->Push(); + errors->SetName("{{type.id}}"); + const base::DictionaryValue* object; + if (!value.GetAsDictionary(&object)) { + errors->AddError("object expected"); + errors->Pop(); + return nullptr; + } + + std::unique_ptr<{{type.id}}> result(new {{type.id}}()); + errors->Push(); + errors->SetName("{{type.id}}"); + {% for property in type.properties %} + {% set value_name = property.name | camelcase_to_hacker_style + "_value" %} + const base::Value* {{value_name}}; + if (object->Get("{{property.name}}", &{{value_name}})) { + errors->SetName("{{property.name}}"); + {% if property.optional %} + result->{{property.name | camelcase_to_hacker_style}}_ = internal::FromValue<{{resolve_type(property).raw_type}}>::Parse(*{{value_name}}, errors); + {% else %} + result->{{property.name | camelcase_to_hacker_style}}_ = internal::FromValue<{{resolve_type(property).raw_type}}>::Parse(*{{value_name}}, errors); + {% endif %} + {% if property.optional %} + } + {% else %} + } else { + errors->AddError("required property missing: {{property.name}}"); + } + {% endif %} + {% endfor %} + errors->Pop(); + errors->Pop(); + if (errors->HasErrors()) + return nullptr; + return result; +} + +std::unique_ptr<base::Value> {{type.id}}::Serialize() const { + std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); + {% for property in type.properties %} + {% set type = resolve_type(property) %} + {% if property.optional %} + if ({{property.name | camelcase_to_hacker_style}}_) + result->Set("{{property.name}}", internal::ToValue({{type.to_raw_type % ("%s_.value()" % property.name | camelcase_to_hacker_style)}})); + {% else %} + result->Set("{{property.name}}", internal::ToValue({{type.to_raw_type % ("%s_" % property.name | camelcase_to_hacker_style)}})); + {% endif %} + {% endfor %} + return std::move(result); +} + +std::unique_ptr<{{type.id}}> {{type.id}}::Clone() const { + ErrorReporter errors; + std::unique_ptr<{{type.id}}> result = Parse(*Serialize(), &errors); + DCHECK(!errors.HasErrors()); + return result; +} + + {% endfor %} +} // namespace {{domain.domain | camelcase_to_hacker_style}} +{% endfor %} + +} // namespace headless
diff --git a/headless/lib/browser/types_h.template b/headless/lib/browser/types_h.template new file mode 100644 index 0000000..0d883ea --- /dev/null +++ b/headless/lib/browser/types_h.template
@@ -0,0 +1,158 @@ +// This file is generated + +// Copyright (c) 2016 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 HEADLESS_PUBLIC_DOMAINS_TYPES_H_ +#define HEADLESS_PUBLIC_DOMAINS_TYPES_H_ + +#include "base/optional.h" +#include "base/values.h" +#include "headless/public/headless_export.h" +#include "headless/public/util/error_reporter.h" + +#include "base/memory/ptr_util.h" + +namespace headless { + +// ------------- Forward declarations and typedefs. + +{% for domain in api.domains %} + +namespace {{domain.domain | camelcase_to_hacker_style}} { + {% for type in domain.types %} + {% if type.type == "object" %} + {% if "properties" in type %} +class {{type.id}}; + {% else %} +using {{type.id}} = base::Value; + {% endif %} + {% endif %} + {% endfor %} +} // namespace {{domain.domain}} +{% endfor %} + +{% for domain in api.domains %} +namespace {{domain.domain | camelcase_to_hacker_style}} { + {% for type in domain.types %} + {% if "enum" in type %} +enum class {{type.id}} { + {% for literal in type.enum %} + {{ literal | dash_to_camelcase | camelcase_to_hacker_style | upper | mangle_enum}}{{',' if not loop.last}} + {% endfor %} +}; + + {% endif %} + {% endfor %} +} // namespace {{domain.domain | camelcase_to_hacker_style}} + +{% endfor %} + +// ------------- Type and builder declarations. +{% for domain in api.domains %} + +namespace {{domain.domain | camelcase_to_hacker_style}} { + {% for type in domain.types %} + {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %} + + {% if type.description %} +// {{type.description}} + {% endif %} +class HEADLESS_EXPORT {{type.id}} { + public: + static {{resolve_type(type).pass_type}} Parse(const base::Value& value, ErrorReporter* errors); + ~{{type.id}}() { } + {% for property in type.properties %} + + {% if property.description %} + // {{property.description}} + {% endif %} + {% if property.optional %} + bool Has{{property.name | to_title_case}}() { return !!{{property.name | camelcase_to_hacker_style}}_; } + {{resolve_type(property).raw_return_type}} Get{{property.name | to_title_case}}() { return {{resolve_type(property).to_raw_return_type % ("%s_.value()" % property.name | camelcase_to_hacker_style)}}; } + void Set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value) { {{property.name | camelcase_to_hacker_style}}_ = {{resolve_type(property).to_pass_type % 'value'}}; } + {% else %} + {{resolve_type(property).raw_return_type}} Get{{property.name | to_title_case}}() { return {{resolve_type(property).to_raw_return_type % ("%s_" % property.name | camelcase_to_hacker_style)}}; } + void Set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value) { {{property.name | camelcase_to_hacker_style}}_ = {{resolve_type(property).to_pass_type % 'value'}}; } + {% endif %} + {% endfor %} + + std::unique_ptr<base::Value> Serialize() const; + {{resolve_type(type).pass_type}} Clone() const; + + template<int STATE> + class {{type.id}}Builder { + public: + enum { + kNoFieldsSet = 0, + {% set count = 0 %} + {% for property in type.properties %} + {% if not(property.optional) %} + {% set count = count + 1 %} + k{{property.name | to_title_case}}Set = 1 << {{count}}, + {% endif %} + {% endfor %} + kAllRequiredFieldsSet = ( + {%- for property in type.properties %} + {% if not(property.optional) %}k{{property.name | to_title_case}}Set | {%endif %} + {% endfor %}0) + }; + + {% for property in type.properties %} + {% if property.optional %} + {{type.id}}Builder<STATE>& Set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value) { + result_->Set{{property.name | to_title_case}}({{resolve_type(property).to_pass_type % 'value'}}); + return *this; + } + {% else %} + {{type.id}}Builder<STATE | k{{property.name | to_title_case}}Set>& Set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value) { + static_assert(!(STATE & k{{property.name | to_title_case}}Set), "property {{property.name}} should not have already been set"); + result_->Set{{property.name | to_title_case}}({{resolve_type(property).to_pass_type % 'value'}}); + return CastState<k{{property.name | to_title_case}}Set>(); + } + {% endif %} + + {% endfor %} + {{resolve_type(type).pass_type}} Build() { + static_assert(STATE == kAllRequiredFieldsSet, "all required fields should have been set"); + return std::move(result_); + } + + private: + friend class {{type.id}}; + {{type.id}}Builder() : result_(new {{type.id}}()) { } + + template<int STEP> {{type.id}}Builder<STATE | STEP>& CastState() { + return *reinterpret_cast<{{type.id}}Builder<STATE | STEP>*>(this); + } + + {{resolve_type(type).type}} result_; + }; + + static {{type.id}}Builder<0> Builder() { + return {{type.id}}Builder<0>(); + } + + private: + {{type.id}}() { } + + {% for property in type.properties %} + {% if property.optional %} + base::Optional<{{resolve_type(property).type}}> {{property.name | camelcase_to_hacker_style}}_; + {% else %} + {{resolve_type(property).type}} {{property.name | camelcase_to_hacker_style}}_; + {% endif %} + {% endfor %} + + DISALLOW_COPY_AND_ASSIGN({{type.id}}); +}; + + {% endfor %} + +} // namespace {{domain.domain | camelcase_to_hacker_style}} +{% endfor %} + +} // namespace headless + +#endif // HEADLESS_PUBLIC_DOMAINS_TYPES_H_
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc new file mode 100644 index 0000000..d67682a --- /dev/null +++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -0,0 +1,113 @@ +// Copyright 2016 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 <memory> + +#include "content/public/test/browser_test.h" +#include "headless/public/domains/page.h" +#include "headless/public/domains/runtime.h" +#include "headless/public/headless_browser.h" +#include "headless/public/headless_devtools_client.h" +#include "headless/public/headless_devtools_target.h" +#include "headless/public/headless_web_contents.h" +#include "headless/test/headless_browser_test.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/size.h" +#include "url/gurl.h" + +namespace headless { + +#define DEVTOOLS_CLIENT_TEST_F(TEST_FIXTURE_NAME) \ + IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \ + class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {} + +// A test fixture which attaches a devtools client before starting the test. +class HeadlessDevToolsClientTest : public HeadlessBrowserTest, + public HeadlessWebContents::Observer { + public: + HeadlessDevToolsClientTest() + : devtools_client_(HeadlessDevToolsClient::Create()) {} + ~HeadlessDevToolsClientTest() override {} + + // HeadlessWebContentsObserver implementation: + void DevToolsTargetReady() override { + EXPECT_TRUE(web_contents_->GetDevToolsTarget()); + web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); + RunDevToolsClientTest(); + } + + virtual void RunDevToolsClientTest() = 0; + + protected: + void RunTest() { + web_contents_ = + browser()->CreateWebContents(GURL("about:blank"), gfx::Size(800, 600)); + web_contents_->AddObserver(this); + + RunAsynchronousTest(); + + web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); + web_contents_->RemoveObserver(this); + web_contents_ = nullptr; + } + + std::unique_ptr<HeadlessWebContents> web_contents_; + std::unique_ptr<HeadlessDevToolsClient> devtools_client_; +}; + +class HeadlessDevToolsClientNavigationTest : public HeadlessDevToolsClientTest { + public: + void RunDevToolsClientTest() override { + EXPECT_TRUE(embedded_test_server()->Start()); + std::unique_ptr<page::NavigateParams> params = + page::NavigateParams::Builder() + .SetUrl(embedded_test_server()->GetURL("/hello.html").spec()) + .Build(); + devtools_client_->GetPage()->Navigate(std::move(params)); + } + + // TODO(skyostil): Wait for a load event once we support them. + void DidFinishNavigation(bool success) override { + EXPECT_TRUE(success); + FinishAsynchronousTest(); + } +}; + +DEVTOOLS_CLIENT_TEST_F(HeadlessDevToolsClientNavigationTest); + +class HeadlessDevToolsClientEvalTest : public HeadlessDevToolsClientTest { + public: + void RunDevToolsClientTest() override { + std::unique_ptr<runtime::EvaluateParams> params = + runtime::EvaluateParams::Builder().SetExpression("1 + 2").Build(); + devtools_client_->GetRuntime()->Evaluate( + std::move(params), + base::Bind(&HeadlessDevToolsClientEvalTest::OnFirstResult, + base::Unretained(this))); + // Test the convenience overload which only takes the required command + // parameters. + devtools_client_->GetRuntime()->Evaluate( + "24 * 7", base::Bind(&HeadlessDevToolsClientEvalTest::OnSecondResult, + base::Unretained(this))); + } + + void OnFirstResult(std::unique_ptr<runtime::EvaluateResult> result) { + int value; + EXPECT_TRUE(result->GetResult()->HasValue()); + EXPECT_TRUE(result->GetResult()->GetValue()->GetAsInteger(&value)); + EXPECT_EQ(3, value); + } + + void OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result) { + int value; + EXPECT_TRUE(result->GetResult()->HasValue()); + EXPECT_TRUE(result->GetResult()->GetValue()->GetAsInteger(&value)); + EXPECT_EQ(168, value); + FinishAsynchronousTest(); + } +}; + +DEVTOOLS_CLIENT_TEST_F(HeadlessDevToolsClientEvalTest); + +} // namespace headless
diff --git a/headless/public/domains/README.md b/headless/public/domains/README.md new file mode 100644 index 0000000..a3f8898c --- /dev/null +++ b/headless/public/domains/README.md
@@ -0,0 +1,3 @@ +The client API domain classes are autogenerated. You can find them under the +out-directory, e.g., out/Debug/gen/headless/public/domains, or in +[Code Search](https://code.google.com/p/chromium/codesearch#search/&q=f%3Agen/headless/public/domains&sq=package:chromium&type=cs).
diff --git a/headless/public/domains/types_unittest.cc b/headless/public/domains/types_unittest.cc new file mode 100644 index 0000000..c665d95 --- /dev/null +++ b/headless/public/domains/types_unittest.cc
@@ -0,0 +1,200 @@ +// Copyright 2016 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/json/json_reader.h" +#include "headless/public/domains/types.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace headless { + +TEST(TypesTest, IntegerProperty) { + std::unique_ptr<accessibility::GetAXNodeParams> object( + accessibility::GetAXNodeParams::Builder().SetNodeId(123).Build()); + EXPECT_TRUE(object); + EXPECT_EQ(123, object->GetNodeId()); + + std::unique_ptr<accessibility::GetAXNodeParams> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ(123, clone->GetNodeId()); +} + +TEST(TypesTest, IntegerPropertyParseError) { + const char* json = "{\"nodeId\": \"foo\"}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(accessibility::GetAXNodeParams::Parse(*object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, BooleanProperty) { + std::unique_ptr<memory::SetPressureNotificationsSuppressedParams> object( + memory::SetPressureNotificationsSuppressedParams::Builder() + .SetSuppressed(true) + .Build()); + EXPECT_TRUE(object); + EXPECT_TRUE(object->GetSuppressed()); + + std::unique_ptr<memory::SetPressureNotificationsSuppressedParams> clone( + object->Clone()); + EXPECT_TRUE(clone); + EXPECT_TRUE(clone->GetSuppressed()); +} + +TEST(TypesTest, BooleanPropertyParseError) { + const char* json = "{\"suppressed\": \"foo\"}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(memory::SetPressureNotificationsSuppressedParams::Parse( + *object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, DoubleProperty) { + std::unique_ptr<page::SetGeolocationOverrideParams> object( + page::SetGeolocationOverrideParams::Builder().SetLatitude(3.14).Build()); + EXPECT_TRUE(object); + EXPECT_EQ(3.14, object->GetLatitude()); + + std::unique_ptr<page::SetGeolocationOverrideParams> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ(3.14, clone->GetLatitude()); +} + +TEST(TypesTest, DoublePropertyParseError) { + const char* json = "{\"latitude\": \"foo\"}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(page::SetGeolocationOverrideParams::Parse(*object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, StringProperty) { + std::unique_ptr<page::NavigateParams> object( + page::NavigateParams::Builder().SetUrl("url").Build()); + EXPECT_TRUE(object); + EXPECT_EQ("url", object->GetUrl()); + + std::unique_ptr<page::NavigateParams> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ("url", clone->GetUrl()); +} + +TEST(TypesTest, StringPropertyParseError) { + const char* json = "{\"url\": false}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(page::NavigateParams::Parse(*object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, EnumProperty) { + std::unique_ptr<runtime::RemoteObject> object( + runtime::RemoteObject::Builder() + .SetType(runtime::RemoteObjectType::UNDEFINED) + .Build()); + EXPECT_TRUE(object); + EXPECT_EQ(runtime::RemoteObjectType::UNDEFINED, object->GetType()); + + std::unique_ptr<runtime::RemoteObject> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ(runtime::RemoteObjectType::UNDEFINED, clone->GetType()); +} + +TEST(TypesTest, EnumPropertyParseError) { + const char* json = "{\"type\": false}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(runtime::RemoteObject::Parse(*object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, ArrayProperty) { + std::vector<int> values; + values.push_back(1); + values.push_back(2); + values.push_back(3); + + std::unique_ptr<dom::QuerySelectorAllResult> object( + dom::QuerySelectorAllResult::Builder().SetNodeIds(values).Build()); + EXPECT_TRUE(object); + EXPECT_EQ(3u, object->GetNodeIds()->size()); + EXPECT_EQ(1, object->GetNodeIds()->at(0)); + EXPECT_EQ(2, object->GetNodeIds()->at(1)); + EXPECT_EQ(3, object->GetNodeIds()->at(2)); + + std::unique_ptr<dom::QuerySelectorAllResult> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ(3u, clone->GetNodeIds()->size()); + EXPECT_EQ(1, clone->GetNodeIds()->at(0)); + EXPECT_EQ(2, clone->GetNodeIds()->at(1)); + EXPECT_EQ(3, clone->GetNodeIds()->at(2)); +} + +TEST(TypesTest, ArrayPropertyParseError) { + const char* json = "{\"nodeIds\": true}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(dom::QuerySelectorAllResult::Parse(*object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, ObjectProperty) { + std::unique_ptr<runtime::RemoteObject> subobject( + runtime::RemoteObject::Builder() + .SetType(runtime::RemoteObjectType::SYMBOL) + .Build()); + std::unique_ptr<runtime::EvaluateResult> object( + runtime::EvaluateResult::Builder() + .SetResult(std::move(subobject)) + .Build()); + EXPECT_TRUE(object); + EXPECT_EQ(runtime::RemoteObjectType::SYMBOL, object->GetResult()->GetType()); + + std::unique_ptr<runtime::EvaluateResult> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ(runtime::RemoteObjectType::SYMBOL, clone->GetResult()->GetType()); +} + +TEST(TypesTest, ObjectPropertyParseError) { + const char* json = "{\"result\": 42}"; + std::unique_ptr<base::Value> object = base::JSONReader::Read(json); + EXPECT_TRUE(object); + + ErrorReporter errors; + EXPECT_FALSE(runtime::EvaluateResult::Parse(*object, &errors)); + EXPECT_TRUE(errors.HasErrors()); +} + +TEST(TypesTest, AnyProperty) { + std::unique_ptr<base::Value> value(new base::FundamentalValue(123)); + std::unique_ptr<accessibility::AXValue> object( + accessibility::AXValue::Builder() + .SetType(accessibility::AXValueType::INTEGER) + .SetValue(std::move(value)) + .Build()); + EXPECT_TRUE(object); + EXPECT_EQ(base::Value::TYPE_INTEGER, object->GetValue()->GetType()); + + std::unique_ptr<accessibility::AXValue> clone(object->Clone()); + EXPECT_TRUE(clone); + EXPECT_EQ(base::Value::TYPE_INTEGER, clone->GetValue()->GetType()); + + int clone_value; + EXPECT_TRUE(clone->GetValue()->GetAsInteger(&clone_value)); + EXPECT_EQ(123, clone_value); +} + +} // namespace headless
diff --git a/headless/public/headless_devtools_client.h b/headless/public/headless_devtools_client.h new file mode 100644 index 0000000..a71ce65 --- /dev/null +++ b/headless/public/headless_devtools_client.h
@@ -0,0 +1,157 @@ +// Copyright 2016 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 HEADLESS_PUBLIC_HEADLESS_DEVTOOLS_CLIENT_H_ +#define HEADLESS_PUBLIC_HEADLESS_DEVTOOLS_CLIENT_H_ + +#include <memory> + +#include "base/macros.h" +#include "headless/public/headless_export.h" + +namespace headless { + +namespace accessibility { +class Domain; +} +namespace animation { +class Domain; +} +namespace application_cache { +class Domain; +} +namespace cache_storage { +class Domain; +} +namespace console { +class Domain; +} +namespace css { +class Domain; +} +namespace database { +class Domain; +} +namespace debugger { +class Domain; +} +namespace device_orientation { +class Domain; +} +namespace dom { +class Domain; +} +namespace dom_debugger { +class Domain; +} +namespace dom_storage { +class Domain; +} +namespace emulation { +class Domain; +} +namespace heap_profiler { +class Domain; +} +namespace indexeddb { +class Domain; +} +namespace input { +class Domain; +} +namespace inspector { +class Domain; +} +namespace io { +class Domain; +} +namespace layer_tree { +class Domain; +} +namespace memory { +class Domain; +} +namespace network { +class Domain; +} +namespace page { +class Domain; +} +namespace profiler { +class Domain; +} +namespace rendering { +class Domain; +} +namespace runtime { +class Domain; +} +namespace security { +class Domain; +} +namespace service_worker { +class Domain; +} +namespace tracing { +class Domain; +} +namespace worker { +class Domain; +} + +// An interface for controlling and receiving events from a devtools target. +class HEADLESS_EXPORT HeadlessDevToolsClient { + public: + virtual ~HeadlessDevToolsClient() {} + + static std::unique_ptr<HeadlessDevToolsClient> Create(); + + // DevTools commands are split into domains which corresponds to the getters + // below. Each domain can be used to send commands and to subscribe to events. + // + // See http://chromedevtools.github.io/debugger-protocol-viewer/ for + // the capabilities of each domain. + virtual accessibility::Domain* GetAccessibility() = 0; + virtual animation::Domain* GetAnimation() = 0; + virtual application_cache::Domain* GetApplicationCache() = 0; + virtual cache_storage::Domain* GetCacheStorage() = 0; + virtual console::Domain* GetConsole() = 0; + virtual css::Domain* GetCSS() = 0; + virtual database::Domain* GetDatabase() = 0; + virtual debugger::Domain* GetDebugger() = 0; + virtual device_orientation::Domain* GetDeviceOrientation() = 0; + virtual dom::Domain* GetDOM() = 0; + virtual dom_debugger::Domain* GetDOMDebugger() = 0; + virtual dom_storage::Domain* GetDOMStorage() = 0; + virtual emulation::Domain* GetEmulation() = 0; + virtual heap_profiler::Domain* GetHeapProfiler() = 0; + virtual indexeddb::Domain* GetIndexedDB() = 0; + virtual input::Domain* GetInput() = 0; + virtual inspector::Domain* GetInspector() = 0; + virtual io::Domain* GetIO() = 0; + virtual layer_tree::Domain* GetLayerTree() = 0; + virtual memory::Domain* GetMemory() = 0; + virtual network::Domain* GetNetwork() = 0; + virtual page::Domain* GetPage() = 0; + virtual profiler::Domain* GetProfiler() = 0; + virtual rendering::Domain* GetRendering() = 0; + virtual runtime::Domain* GetRuntime() = 0; + virtual security::Domain* GetSecurity() = 0; + virtual service_worker::Domain* GetServiceWorker() = 0; + virtual tracing::Domain* GetTracing() = 0; + virtual worker::Domain* GetWorker() = 0; + + // TODO(skyostil): Add notification for disconnection. + + private: + friend class HeadlessDevToolsClientImpl; + + HeadlessDevToolsClient() {} + + DISALLOW_COPY_AND_ASSIGN(HeadlessDevToolsClient); +}; + +} // namespace headless + +#endif // HEADLESS_PUBLIC_HEADLESS_DEVTOOLS_CLIENT_H_
diff --git a/headless/public/headless_devtools_target.h b/headless/public/headless_devtools_target.h new file mode 100644 index 0000000..941fe6f5 --- /dev/null +++ b/headless/public/headless_devtools_target.h
@@ -0,0 +1,37 @@ +// Copyright 2016 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 HEADLESS_PUBLIC_HEADLESS_DEVTOOLS_TARGET_H_ +#define HEADLESS_PUBLIC_HEADLESS_DEVTOOLS_TARGET_H_ + +#include "base/macros.h" +#include "headless/public/headless_export.h" + +namespace headless { +class HeadlessDevToolsClient; + +// A target which can be controlled and inspected using DevTools. +class HEADLESS_EXPORT HeadlessDevToolsTarget { + public: + HeadlessDevToolsTarget() {} + virtual ~HeadlessDevToolsTarget() {} + + // Attach or detach a client to this target. A client must be attached in + // order to send commands or receive notifications from the target. + // + // A single client may be attached to at most one target at a time. Note that + // currently also only one client may be attached to a single target at a + // time. + // + // |client| must outlive this target. + virtual void AttachClient(HeadlessDevToolsClient* client) = 0; + virtual void DetachClient(HeadlessDevToolsClient* client) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(HeadlessDevToolsTarget); +}; + +} // namespace headless + +#endif // HEADLESS_PUBLIC_HEADLESS_DEVTOOLS_TARGET_H_
diff --git a/headless/public/headless_web_contents.h b/headless/public/headless_web_contents.h index 04ac95300..d9b29b7 100644 --- a/headless/public/headless_web_contents.h +++ b/headless/public/headless_web_contents.h
@@ -12,6 +12,7 @@ #include "url/gurl.h" namespace headless { +class HeadlessDevToolsTarget; // Class representing contents of a browser tab. Should be accessed from browser // main thread. @@ -23,12 +24,12 @@ class Observer { public: // All the following notifications will be called on browser main thread. - virtual void DocumentOnLoadCompletedInMainFrame(){}; - virtual void DidFinishNavigation(bool success){}; + virtual void DocumentOnLoadCompletedInMainFrame() {} + virtual void DidFinishNavigation(bool success) {} - // After this event, this HeadlessWebContents instance is ready to be - // controlled using a DevTools client. - virtual void WebContentsReady(){}; + // Indicates that this HeadlessWebContents instance is now ready to be + // inspected using a HeadlessDevToolsClient. + virtual void DevToolsTargetReady() {} protected: Observer() {} @@ -43,6 +44,11 @@ virtual void AddObserver(Observer* observer) = 0; virtual void RemoveObserver(Observer* observer) = 0; + // Return a DevTools target corresponding to this tab. Note that this method + // won't return a valid value until Observer::DevToolsTargetReady has been + // signaled. + virtual HeadlessDevToolsTarget* GetDevToolsTarget() = 0; + private: friend class HeadlessWebContentsImpl; HeadlessWebContents() {}
diff --git a/headless/public/internal/message_dispatcher.h b/headless/public/internal/message_dispatcher.h new file mode 100644 index 0000000..32352f4 --- /dev/null +++ b/headless/public/internal/message_dispatcher.h
@@ -0,0 +1,31 @@ +// Copyright 2016 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 HEADLESS_PUBLIC_INTERNAL_MESSAGE_DISPATCHER_H_ +#define HEADLESS_PUBLIC_INTERNAL_MESSAGE_DISPATCHER_H_ + +namespace headless { +namespace internal { + +// An internal interface for sending DevTools messages from the domain agents. +class MessageDispatcher { + public: + virtual void SendMessage( + const char* method, + std::unique_ptr<base::Value> params, + base::Callback<void(const base::Value&)> callback) = 0; + virtual void SendMessage(const char* method, + std::unique_ptr<base::Value> params, + base::Callback<void()> callback) = 0; + virtual void SendMessage( + const char* method, + base::Callback<void(const base::Value&)> callback) = 0; + virtual void SendMessage(const char* method, + base::Callback<void()> callback) = 0; +}; + +} // namespace internal +} // namespace headless + +#endif // HEADLESS_PUBLIC_INTERNAL_MESSAGE_DISPATCHER_H_
diff --git a/headless/public/internal/value_conversions.h b/headless/public/internal/value_conversions.h new file mode 100644 index 0000000..17c6eda --- /dev/null +++ b/headless/public/internal/value_conversions.h
@@ -0,0 +1,163 @@ +// Copyright 2016 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 HEADLESS_PUBLIC_INTERNAL_VALUE_CONVERSIONS_H_ +#define HEADLESS_PUBLIC_INTERNAL_VALUE_CONVERSIONS_H_ + +#include <memory> + +#include "base/memory/ptr_util.h" +#include "headless/public/util/error_reporter.h" + +namespace headless { +namespace internal { + +// Generic conversion from a type to a base::Value. Implemented in +// type_conversions.h after all type-specific ToValueImpls have been defined. +template <typename T> +std::unique_ptr<base::Value> ToValue(const T& value); + +// Generic conversion from a base::Value to a type. Note that this generic +// variant is never defined. Instead, we declare a specific template +// specialization for all the used types. +template <typename T> +struct FromValue { + static std::unique_ptr<T> Parse(const base::Value& value, + ErrorReporter* errors); +}; + +// ToValueImpl is a helper used by the ToValue template for dispatching into +// type-specific serializers. It uses a dummy |T*| argument as a way to +// partially specialize vector types. +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(int value, T*) { + return base::WrapUnique(new base::FundamentalValue(value)); +} + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(double value, T*) { + return base::WrapUnique(new base::FundamentalValue(value)); +} + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(bool value, T*) { + return base::WrapUnique(new base::FundamentalValue(value)); +} + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const std::string& value, T*) { + return base::WrapUnique(new base::StringValue(value)); +} + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const base::Value& value, T*) { + return value.CreateDeepCopy(); +} + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const std::vector<T>& vector, + const std::vector<T>*) { + std::unique_ptr<base::ListValue> result(new base::ListValue()); + for (const auto& it : vector) + result->Append(ToValue(it)); + return std::move(result); +} + +template <typename T> +std::unique_ptr<base::Value> ToValueImpl(const std::unique_ptr<T>& value, + std::unique_ptr<T>*) { + return ToValue(value.get()); +} + +// FromValue specializations for basic types. +template <> +struct FromValue<bool> { + static bool Parse(const base::Value& value, ErrorReporter* errors) { + bool result = false; + if (!value.GetAsBoolean(&result)) + errors->AddError("boolean value expected"); + return result; + } +}; + +template <> +struct FromValue<int> { + static int Parse(const base::Value& value, ErrorReporter* errors) { + int result = 0; + if (!value.GetAsInteger(&result)) + errors->AddError("integer value expected"); + return result; + } +}; + +template <> +struct FromValue<double> { + static double Parse(const base::Value& value, ErrorReporter* errors) { + double result = 0; + if (!value.GetAsDouble(&result)) + errors->AddError("double value expected"); + return result; + } +}; + +template <> +struct FromValue<std::string> { + static std::string Parse(const base::Value& value, ErrorReporter* errors) { + std::string result; + if (!value.GetAsString(&result)) + errors->AddError("string value expected"); + return result; + } +}; + +template <> +struct FromValue<base::DictionaryValue> { + static std::unique_ptr<base::DictionaryValue> Parse(const base::Value& value, + ErrorReporter* errors) { + const base::DictionaryValue* result; + if (!value.GetAsDictionary(&result)) { + errors->AddError("dictionary value expected"); + return nullptr; + } + return result->CreateDeepCopy(); + } +}; + +template <> +struct FromValue<base::Value> { + static std::unique_ptr<base::Value> Parse(const base::Value& value, + ErrorReporter* errors) { + return value.CreateDeepCopy(); + } +}; + +template <typename T> +struct FromValue<std::unique_ptr<T>> { + static std::unique_ptr<T> Parse(const base::Value& value, + ErrorReporter* errors) { + return FromValue<T>::Parse(value, errors); + } +}; + +template <typename T> +struct FromValue<std::vector<T>> { + static std::vector<T> Parse(const base::Value& value, ErrorReporter* errors) { + std::vector<T> result; + const base::ListValue* list; + if (!value.GetAsList(&list)) { + errors->AddError("list value expected"); + return result; + } + errors->Push(); + for (const auto& item : *list) + result.push_back(FromValue<T>::Parse(*item, errors)); + errors->Pop(); + return result; + } +}; + +} // namespace internal +} // namespace headless + +#endif // HEADLESS_PUBLIC_INTERNAL_VALUE_CONVERSIONS_H_
diff --git a/headless/public/util/maybe.h b/headless/public/util/maybe.h deleted file mode 100644 index 18540a36..0000000 --- a/headless/public/util/maybe.h +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2016 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 HEADLESS_PUBLIC_UTIL_MAYBE_H_ -#define HEADLESS_PUBLIC_UTIL_MAYBE_H_ - -#include <algorithm> - -#include "base/logging.h" -#include "base/macros.h" - -namespace headless { - -// A simple Maybe which may or may not have a value. Based on v8::Maybe. -template <typename T> -class Maybe { - public: - Maybe() : has_value_(false) {} - - bool IsNothing() const { return !has_value_; } - bool IsJust() const { return has_value_; } - - // Will crash if the Maybe<> is nothing. - T& FromJust() { - DCHECK(IsJust()); - return value_; - } - const T& FromJust() const { - DCHECK(IsJust()); - return value_; - } - - T FromMaybe(const T& default_value) const { - return has_value_ ? value_ : default_value; - } - - bool operator==(const Maybe& other) const { - return (IsJust() == other.IsJust()) && - (!IsJust() || FromJust() == other.FromJust()); - } - - bool operator!=(const Maybe& other) const { return !operator==(other); } - - Maybe& operator=(Maybe&& other) { - has_value_ = other.has_value_; - value_ = std::move(other.value_); - return *this; - } - - Maybe& operator=(const Maybe& other) { - has_value_ = other.has_value_; - value_ = other.value_; - return *this; - } - - Maybe(const Maybe& other) = default; - Maybe(Maybe&& other) = default; - - private: - template <class U> - friend Maybe<U> Nothing(); - template <class U> - friend Maybe<U> Just(const U& u); - template <class U> - friend Maybe<typename std::remove_reference<U>::type> Just(U&& u); - - explicit Maybe(const T& t) : has_value_(true), value_(t) {} - explicit Maybe(T&& t) : has_value_(true), value_(std::move(t)) {} - - bool has_value_; - T value_; -}; - -template <class T> -Maybe<T> Nothing() { - return Maybe<T>(); -} - -template <class T> -Maybe<T> Just(const T& t) { - return Maybe<T>(t); -} - -template <class T> -Maybe<typename std::remove_reference<T>::type> Just(T&& t) { - return Maybe<typename std::remove_reference<T>::type>(std::move(t)); -} - -} // namespace headless - -#endif // HEADLESS_PUBLIC_UTIL_MAYBE_H_
diff --git a/headless/public/util/maybe_unittest.cc b/headless/public/util/maybe_unittest.cc deleted file mode 100644 index fb926961..0000000 --- a/headless/public/util/maybe_unittest.cc +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2016 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 "headless/public/util/maybe.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace headless { -namespace { - -class MoveOnlyType { - public: - MoveOnlyType() {} - MoveOnlyType(MoveOnlyType&& other) {} - - void operator=(MoveOnlyType&& other) {} - - private: - DISALLOW_COPY_AND_ASSIGN(MoveOnlyType); -}; - -} // namespace - -TEST(MaybeTest, Nothing) { - Maybe<int> maybe; - EXPECT_TRUE(maybe.IsNothing()); - EXPECT_FALSE(maybe.IsJust()); -} - -TEST(MaybeTest, Just) { - Maybe<int> maybe = Just(1); - EXPECT_FALSE(maybe.IsNothing()); - EXPECT_TRUE(maybe.IsJust()); - EXPECT_EQ(1, maybe.FromJust()); - - const Maybe<int> const_maybe = Just(2); - EXPECT_EQ(2, const_maybe.FromJust()); -} - -TEST(MaybeTest, Equality) { - Maybe<int> a; - Maybe<int> b; - EXPECT_EQ(a, b); - EXPECT_EQ(b, a); - - a = Just(1); - EXPECT_NE(a, b); - EXPECT_NE(b, a); - - b = Just(2); - EXPECT_NE(a, b); - EXPECT_NE(b, a); - - b = Just(1); - EXPECT_EQ(a, b); - EXPECT_EQ(b, a); -} - -TEST(MaybeTest, Assignment) { - Maybe<int> a = Just(1); - Maybe<int> b = Nothing<int>(); - EXPECT_NE(a, b); - - b = a; - EXPECT_EQ(a, b); -} - -TEST(MaybeTest, MoveOnlyType) { - MoveOnlyType value; - Maybe<MoveOnlyType> a = Just(std::move(value)); - EXPECT_TRUE(a.IsJust()); - - Maybe<MoveOnlyType> b = Just(MoveOnlyType()); - EXPECT_TRUE(b.IsJust()); - - Maybe<MoveOnlyType> c = Nothing<MoveOnlyType>(); - c = std::move(a); - EXPECT_TRUE(c.IsJust()); - - MoveOnlyType d = std::move(b.FromJust()); -} - -} // namespace headless
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc index 0525782..2424231 100644 --- a/headless/test/headless_browser_test.cc +++ b/headless/test/headless_browser_test.cc
@@ -98,6 +98,7 @@ void HeadlessBrowserTest::RunAsynchronousTest() { base::MessageLoop::ScopedNestableTaskAllower nestable_allower( base::MessageLoop::current()); + EXPECT_FALSE(run_loop_); run_loop_ = base::WrapUnique(new base::RunLoop()); run_loop_->Run(); run_loop_ = nullptr;
diff --git a/ios/chrome/browser/ios_chrome_io_thread.mm b/ios/chrome/browser/ios_chrome_io_thread.mm index 763c028..f0fa384 100644 --- a/ios/chrome/browser/ios_chrome_io_thread.mm +++ b/ios/chrome/browser/ios_chrome_io_thread.mm
@@ -54,7 +54,6 @@ #include "net/cert/ct_verifier.h" #include "net/cert/multi_log_ct_verifier.h" #include "net/cert/multi_threaded_cert_verifier.h" -#include "net/cert_net/nss_ocsp.h" #include "net/cookies/cookie_monster.h" #include "net/cookies/cookie_store.h" #include "net/dns/host_cache.h" @@ -146,17 +145,11 @@ class SystemURLRequestContext : public net::URLRequestContext { public: SystemURLRequestContext() { -#if defined(USE_NSS_VERIFIER) - net::SetURLRequestContextForNSSHttpIO(this); -#endif } private: ~SystemURLRequestContext() override { AssertNoURLRequests(); -#if defined(USE_NSS_VERIFIER) - net::SetURLRequestContextForNSSHttpIO(nullptr); -#endif } }; @@ -389,10 +382,6 @@ TRACE_EVENT0("startup", "IOSChromeIOThread::Init"); DCHECK_CURRENTLY_ON(web::WebThread::IO); -#if defined(USE_NSS_VERIFIER) - net::SetMessageLoopForNSSHttpIO(); -#endif - const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); @@ -491,10 +480,6 @@ } void IOSChromeIOThread::CleanUp() { -#if defined(USE_NSS_VERIFIER) - net::ShutdownNSSHttpIO(); -#endif - system_url_request_context_getter_ = nullptr; // Release objects that the net::URLRequestContext could have been pointing
diff --git a/ios/chrome/common/material_timing.h b/ios/chrome/common/material_timing.h index 035128a..5e433671 100644 --- a/ios/chrome/common/material_timing.h +++ b/ios/chrome/common/material_timing.h
@@ -36,16 +36,21 @@ // Returns a timing funtion related to the given |curve|. CAMediaTimingFunction* TimingFunction(Curve curve); +} // material +} // ios + +@interface UIView (CrMaterialAnimations) + // Performs a standard UIView animation using a material timing |curve|. // Note: any curve option specified in |options| will be ignored in favor of the // specified curve value. // See also: +[UIView animateWithDuration:delay:animations:completion]. -void Animate(NSTimeInterval duration, - NSTimeInterval delay, - Curve curve, - UIViewAnimationOptions options, - void (^animations)(void), - void (^completion)(BOOL)); ++ (void)cr_animateWithDuration:(NSTimeInterval)duration + delay:(NSTimeInterval)delay + curve:(ios::material::Curve)curve + options:(UIViewAnimationOptions)options + animations:(void (^)(void))animations + completion:(void (^)(BOOL finished))completion; // Performs a standard UIView transition animation using a material timing // |curve|. @@ -53,14 +58,13 @@ // specified curve value. // See also: // +[UIView transitionWithView:duration:options:animations:completion]. -void Transition(UIView* view, - NSTimeInterval duration, - Curve curve, - UIViewAnimationOptions options, - void (^animations)(void), - void (^completion)(BOOL)); ++ (void)cr_transitionWithView:(UIView*)view + duration:(NSTimeInterval)duration + curve:(ios::material::Curve)curve + options:(UIViewAnimationOptions)options + animations:(void (^)(void))animations + completion:(void (^)(BOOL finished))completion; -} // material -} // ios +@end #endif // IOS_CHROME_COMMON_MATERIAL_TIMING_H_
diff --git a/ios/chrome/common/material_timing.mm b/ios/chrome/common/material_timing.mm index 4f81b49..d883aaca 100644 --- a/ios/chrome/common/material_timing.mm +++ b/ios/chrome/common/material_timing.mm
@@ -67,12 +67,17 @@ } } -void Animate(NSTimeInterval duration, - NSTimeInterval delay, - Curve curve, - UIViewAnimationOptions options, - void (^animations)(void), - void (^completion)(BOOL)) { +} // material +} // ios + +@implementation UIView (CrMaterialAnimations) + ++ (void)cr_animateWithDuration:(NSTimeInterval)duration + delay:(NSTimeInterval)delay + curve:(ios::material::Curve)curve + options:(UIViewAnimationOptions)options + animations:(void (^)(void))animations + completion:(void (^)(BOOL finished))completion { [CATransaction begin]; [CATransaction setAnimationTimingFunction:TimingFunction(curve)]; [UIView animateWithDuration:duration @@ -83,12 +88,12 @@ [CATransaction commit]; } -void Transition(UIView* view, - NSTimeInterval duration, - Curve curve, - UIViewAnimationOptions options, - void (^animations)(void), - void (^completion)(BOOL)) { ++ (void)cr_transitionWithView:(UIView*)view + duration:(NSTimeInterval)duration + curve:(ios::material::Curve)curve + options:(UIViewAnimationOptions)options + animations:(void (^)(void))animations + completion:(void (^)(BOOL finished))completion { [CATransaction begin]; [CATransaction setAnimationTimingFunction:TimingFunction(curve)]; [UIView transitionWithView:view @@ -99,5 +104,4 @@ [CATransaction commit]; } -} // material -} // ios +@end
diff --git a/ios/crnet/crnet_environment.mm b/ios/crnet/crnet_environment.mm index b564111..f8c98ed 100644 --- a/ios/crnet/crnet_environment.mm +++ b/ios/crnet/crnet_environment.mm
@@ -26,7 +26,6 @@ #include "base/threading/worker_pool.h" #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_filter.h" -#include "crypto/nss_util.h" #include "ios/crnet/sdch_owner_pref_storage.h" #include "ios/net/cookies/cookie_store_ios.h" #include "ios/net/crn_http_protocol_handler.h" @@ -38,7 +37,6 @@ #include "net/base/network_change_notifier.h" #include "net/base/sdch_manager.h" #include "net/cert/cert_verifier.h" -#include "net/cert_net/nss_ocsp.h" #include "net/cookies/cookie_store.h" #include "net/http/http_auth_handler_factory.h" #include "net/http/http_cache.h" @@ -154,14 +152,6 @@ url::Initialize(); base::CommandLine::Init(0, nullptr); -#if defined(USE_NSS_VERIFIER) - // This needs to happen on the main thread. NSPR's initialization sets up its - // memory allocator; if this is not done before other threads are created, - // this initialization can race to cause accidental free/allocation - // mismatches. - crypto::EnsureNSPRInit(); -#endif - // Without doing this, StatisticsRecorder::FactoryGet() leaks one histogram // per call after the first for a given name. base::StatisticsRecorder::Initialize(); @@ -292,9 +282,6 @@ proxy_config_service_ = net::ProxyService::CreateSystemProxyConfigService( network_io_thread_->task_runner(), nullptr); -#if defined(USE_NSS_VERIFIER) - net::SetURLRequestContextForNSSHttpIO(main_context_.get()); -#endif main_context_getter_ = new CrNetURLRequestContextGetter( main_context_.get(), network_io_thread_->task_runner()); base::subtle::MemoryBarrier(); @@ -312,9 +299,6 @@ CrNetEnvironment::~CrNetEnvironment() { net::HTTPProtocolHandlerDelegate::SetInstance(nullptr); -#if defined(USE_NSS_VERIFIER) - net::SetURLRequestContextForNSSHttpIO(nullptr); -#endif } net::URLRequestContextGetter* CrNetEnvironment::GetMainContextGetter() {
diff --git a/ios/web/app/web_main_loop.mm b/ios/web/app/web_main_loop.mm index 017ffa4..f02ca85 100644 --- a/ios/web/app/web_main_loop.mm +++ b/ios/web/app/web_main_loop.mm
@@ -19,7 +19,6 @@ #include "base/process/process_metrics.h" #include "base/system_monitor/system_monitor.h" #include "base/threading/thread_restrictions.h" -#include "crypto/nss_util.h" #include "ios/web/net/cookie_notification_bridge.h" #include "ios/web/public/app/web_main_parts.h" #include "ios/web/public/web_client.h" @@ -52,14 +51,6 @@ void WebMainLoop::EarlyInitialization() { if (parts_) { parts_->PreEarlyInitialization(); - } - -#if defined(USE_NSS_VERIFIER) - // We want to be sure to init NSPR on the main thread. - crypto::EnsureNSPRInit(); -#endif - - if (parts_) { parts_->PostEarlyInitialization(); } }
diff --git a/net/BUILD.gn b/net/BUILD.gn index 0e282398..cbea3b80 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -160,77 +160,6 @@ ] } - if (use_openssl) { - sources -= [ - "base/nss_memio.c", - "base/nss_memio.h", - "cert/ct_log_verifier_nss.cc", - "cert/ct_objects_extractor_nss.cc", - "cert/jwk_serializer_nss.cc", - "cert/scoped_nss_types.h", - "cert/x509_util_nss.cc", - "quic/crypto/aead_base_decrypter_nss.cc", - "quic/crypto/aead_base_encrypter_nss.cc", - "quic/crypto/aes_128_gcm_12_decrypter_nss.cc", - "quic/crypto/aes_128_gcm_12_encrypter_nss.cc", - "quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc", - "quic/crypto/chacha20_poly1305_rfc7539_encrypter_nss.cc", - "quic/crypto/channel_id_nss.cc", - "quic/crypto/p256_key_exchange_nss.cc", - "quic/crypto/proof_source_chromium_nss.cc", - "socket/nss_ssl_util.cc", - "socket/nss_ssl_util.h", - "socket/ssl_client_socket_nss.cc", - "socket/ssl_client_socket_nss.h", - "socket/ssl_server_socket_nss.cc", - "socket/ssl_server_socket_nss.h", - "ssl/token_binding_nss.cc", - ] - if (is_ios) { - sources -= [ - "cert/x509_util_ios.cc", - "cert/x509_util_ios.h", - ] - } - } else { - sources -= [ - "cert/ct_log_verifier_openssl.cc", - "cert/ct_objects_extractor_openssl.cc", - "cert/jwk_serializer_openssl.cc", - "cert/x509_util_openssl.cc", - "cert/x509_util_openssl.h", - "quic/crypto/aead_base_decrypter_openssl.cc", - "quic/crypto/aead_base_encrypter_openssl.cc", - "quic/crypto/aes_128_gcm_12_decrypter_openssl.cc", - "quic/crypto/aes_128_gcm_12_encrypter_openssl.cc", - "quic/crypto/chacha20_poly1305_rfc7539_decrypter_openssl.cc", - "quic/crypto/chacha20_poly1305_rfc7539_encrypter_openssl.cc", - "quic/crypto/channel_id_openssl.cc", - "quic/crypto/p256_key_exchange_openssl.cc", - "quic/crypto/proof_source_chromium_openssl.cc", - "quic/crypto/scoped_evp_aead_ctx.cc", - "quic/crypto/scoped_evp_aead_ctx.h", - "socket/ssl_client_socket_openssl.cc", - "socket/ssl_client_socket_openssl.h", - "socket/ssl_server_socket_openssl.cc", - "socket/ssl_server_socket_openssl.h", - "ssl/openssl_ssl_util.cc", - "ssl/openssl_ssl_util.h", - "ssl/ssl_client_session_cache_openssl.cc", - "ssl/ssl_client_session_cache_openssl.h", - "ssl/ssl_key_logger.cc", - "ssl/ssl_key_logger.h", - "ssl/ssl_platform_key.h", - "ssl/ssl_platform_key_task_runner.cc", - "ssl/ssl_platform_key_task_runner.h", - "ssl/test_ssl_private_key.cc", - "ssl/test_ssl_private_key.h", - "ssl/threaded_ssl_private_key.cc", - "ssl/threaded_ssl_private_key.h", - "ssl/token_binding_openssl.cc", - ] - } - if (!use_openssl_certs) { sources -= [ "base/crypto_module_openssl.cc", @@ -302,40 +231,26 @@ "ssl/client_key_store.h", "ssl/ssl_platform_key_nss.cc", ] - } else if (use_openssl) { + } else { # 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 (!use_nss_verifier) { + if (!use_nss_certs) { # These files are part of the partial implementation of NSS for # cert verification, so keep them in that case. 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/x509_util_nss.cc", "cert_net/nss_ocsp.cc", "cert_net/nss_ocsp.h", ] } - if (is_ios && use_nss_verifier) { - sources -= [ - "cert/cert_verify_proc_ios.cc", - "cert/cert_verify_proc_ios.h", - "cert/x509_certificate_openssl_ios.cc", - ] - - deps += [ - "//net/third_party/nss/ssl:libssl", - "//third_party/nss", - "//third_party/nss:nspr", - ] - } - if (is_chromecast && use_nss_certs) { sources += [ "ssl/ssl_platform_key_chromecast.cc" ] sources -= [ "ssl/ssl_platform_key_nss.cc" ] @@ -380,6 +295,7 @@ "base/network_interfaces_mac.cc", "base/network_interfaces_mac.h", "base/platform_mime_util_mac.mm", + "cert/test_root_certs_mac.cc", "proxy/proxy_resolver_mac.cc", "proxy/proxy_server_mac.cc", ] @@ -387,11 +303,6 @@ sources -= [ "disk_cache/blockfile/file_posix.cc" ] } - if (is_ios && !use_nss_verifier) { - net_unfiltered_sources += [ "cert/test_root_certs_mac.cc" ] - sources -= [ "cert/x509_certificate_ios.cc" ] - } - if (is_ios || is_mac) { sources += gypi_values.net_base_mac_ios_sources } @@ -721,7 +632,7 @@ public_deps += [ "//third_party/protobuf:py_proto" ] } - if (use_nss_verifier) { + if (use_nss_certs) { public_deps += [ "//crypto:platform" ] } @@ -1462,11 +1373,9 @@ data = [ "data/", ] - data_deps = [] - - if (use_openssl) { - data_deps += [ "third_party/nist-pkits/" ] - } + data_deps = [ + "third_party/nist-pkits/", + ] if (is_linux || is_mac || is_win) { deps += [ @@ -1525,15 +1434,6 @@ } } - if (use_openssl) { - sources -= [ "quic/test_tools/crypto_test_utils_nss.cc" ] - } else { - sources -= [ - "quic/test_tools/crypto_test_utils_openssl.cc", - "ssl/ssl_client_session_cache_openssl_unittest.cc", - ] - } - if (use_kerberos) { defines += [ "USE_KERBEROS" ] } @@ -1551,7 +1451,7 @@ sources -= [ "http/http_auth_handler_negotiate_unittest.cc" ] } - if (!use_nss_verifier) { + if (!use_nss_certs) { # Only include this test when using NSS for cert verification. sources -= [ "cert_net/nss_ocsp_unittest.cc" ] }
diff --git a/net/base/nss_memio.c b/net/base/nss_memio.c deleted file mode 100644 index 895b7b2..0000000 --- a/net/base/nss_memio.c +++ /dev/null
@@ -1,541 +0,0 @@ -// Copyright (c) 2008 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. -// Written in NSPR style to also be suitable for adding to the NSS demo suite - -/* memio is a simple NSPR I/O layer that lets you decouple NSS from - * the real network. It's rather like openssl's memory bio, - * and is useful when your app absolutely, positively doesn't - * want to let NSS do its own networking. - */ - -#include <stdlib.h> -#include <string.h> - -#include <prerror.h> -#include <prinit.h> -#include <prlog.h> - -#include "nss_memio.h" - -/*--------------- private memio types -----------------------*/ - -/*---------------------------------------------------------------------- - Simple private circular buffer class. Size cannot be changed once allocated. -----------------------------------------------------------------------*/ - -struct memio_buffer { - int head; /* where to take next byte out of buf */ - int tail; /* where to put next byte into buf */ - int bufsize; /* number of bytes allocated to buf */ - /* TODO(port): error handling is pessimistic right now. - * Once an error is set, the socket is considered broken - * (PR_WOULD_BLOCK_ERROR not included). - */ - PRErrorCode last_err; - char *buf; -}; - - -/* The 'secret' field of a PRFileDesc created by memio_CreateIOLayer points - * to one of these. - * In the public header, we use struct memio_Private as a typesafe alias - * for this. This causes a few ugly typecasts in the private file, but - * seems safer. - */ -struct PRFilePrivate { - /* read requests are satisfied from this buffer */ - struct memio_buffer readbuf; - - /* write requests are satisfied from this buffer */ - struct memio_buffer writebuf; - - /* SSL needs to know socket peer's name */ - PRNetAddr peername; - - /* if set, empty I/O returns EOF instead of EWOULDBLOCK */ - int eof; - - /* if set, the number of bytes requested from readbuf that were not - * fulfilled (due to readbuf being empty) */ - int read_requested; -}; - -/*--------------- private memio_buffer functions ---------------------*/ - -/* Forward declarations. */ - -/* Allocate a memio_buffer of given size. */ -static void memio_buffer_new(struct memio_buffer *mb, int size); - -/* Deallocate a memio_buffer allocated by memio_buffer_new. */ -static void memio_buffer_destroy(struct memio_buffer *mb); - -/* How many bytes can be read out of the buffer without wrapping */ -static int memio_buffer_used_contiguous(const struct memio_buffer *mb); - -/* How many bytes exist after the wrap? */ -static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb); - -/* How many bytes can be written into the buffer without wrapping */ -static int memio_buffer_unused_contiguous(const struct memio_buffer *mb); - -/* Write n bytes into the buffer. Returns number of bytes written. */ -static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n); - -/* Read n bytes from the buffer. Returns number of bytes read. */ -static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n); - -/* Allocate a memio_buffer of given size. */ -static void memio_buffer_new(struct memio_buffer *mb, int size) -{ - mb->head = 0; - mb->tail = 0; - mb->bufsize = size; - mb->buf = malloc(size); -} - -/* Deallocate a memio_buffer allocated by memio_buffer_new. */ -static void memio_buffer_destroy(struct memio_buffer *mb) -{ - free(mb->buf); - mb->buf = NULL; - mb->bufsize = 0; - mb->head = 0; - mb->tail = 0; -} - -/* How many bytes can be read out of the buffer without wrapping */ -static int memio_buffer_used_contiguous(const struct memio_buffer *mb) -{ - return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head); -} - -/* How many bytes exist after the wrap? */ -static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb) -{ - return (mb->tail >= mb->head) ? 0 : mb->tail; -} - -/* How many bytes can be written into the buffer without wrapping */ -static int memio_buffer_unused_contiguous(const struct memio_buffer *mb) -{ - if (mb->head > mb->tail) return mb->head - mb->tail - 1; - return mb->bufsize - mb->tail - (mb->head == 0); -} - -/* Write n bytes into the buffer. Returns number of bytes written. */ -static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n) -{ - int len; - int transferred = 0; - - /* Handle part before wrap */ - len = PR_MIN(n, memio_buffer_unused_contiguous(mb)); - if (len > 0) { - /* Buffer not full */ - memcpy(&mb->buf[mb->tail], buf, len); - mb->tail += len; - if (mb->tail == mb->bufsize) - mb->tail = 0; - n -= len; - buf += len; - transferred += len; - - /* Handle part after wrap */ - len = PR_MIN(n, memio_buffer_unused_contiguous(mb)); - if (len > 0) { - /* Output buffer still not full, input buffer still not empty */ - memcpy(&mb->buf[mb->tail], buf, len); - mb->tail += len; - if (mb->tail == mb->bufsize) - mb->tail = 0; - transferred += len; - } - } - - return transferred; -} - - -/* Read n bytes from the buffer. Returns number of bytes read. */ -static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n) -{ - int len; - int transferred = 0; - - /* Handle part before wrap */ - len = PR_MIN(n, memio_buffer_used_contiguous(mb)); - if (len) { - memcpy(buf, &mb->buf[mb->head], len); - mb->head += len; - if (mb->head == mb->bufsize) - mb->head = 0; - n -= len; - buf += len; - transferred += len; - - /* Handle part after wrap */ - len = PR_MIN(n, memio_buffer_used_contiguous(mb)); - if (len) { - memcpy(buf, &mb->buf[mb->head], len); - mb->head += len; - if (mb->head == mb->bufsize) - mb->head = 0; - transferred += len; - } - } - - return transferred; -} - -/*--------------- private memio functions -----------------------*/ - -static PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd) -{ - struct PRFilePrivate *secret = fd->secret; - memio_buffer_destroy(&secret->readbuf); - memio_buffer_destroy(&secret->writebuf); - free(secret); - fd->dtor(fd); - return PR_SUCCESS; -} - -static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how) -{ - /* TODO: pass shutdown status to app somehow */ - return PR_SUCCESS; -} - -/* If there was a network error in the past taking bytes - * out of the buffer, return it to the next call that - * tries to read from an empty buffer. - */ -static int PR_CALLBACK memio_Recv(PRFileDesc *fd, void *buf, PRInt32 len, - PRIntn flags, PRIntervalTime timeout) -{ - struct PRFilePrivate *secret; - struct memio_buffer *mb; - int rv; - - if (flags) { - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return -1; - } - - secret = fd->secret; - mb = &secret->readbuf; - PR_ASSERT(mb->bufsize); - rv = memio_buffer_get(mb, buf, len); - if (rv == 0 && !secret->eof) { - secret->read_requested = len; - /* If there is no more data in the buffer, report any pending errors - * that were previously observed. Note that both the readbuf and the - * writebuf are checked for errors, since the application may have - * encountered a socket error while writing that would otherwise not - * be reported until the application attempted to write again - which - * it may never do. - */ - if (mb->last_err) - PR_SetError(mb->last_err, 0); - else if (secret->writebuf.last_err) - PR_SetError(secret->writebuf.last_err, 0); - else - PR_SetError(PR_WOULD_BLOCK_ERROR, 0); - return -1; - } - - secret->read_requested = 0; - return rv; -} - -static int PR_CALLBACK memio_Read(PRFileDesc *fd, void *buf, PRInt32 len) -{ - /* pull bytes from buffer */ - return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT); -} - -static int PR_CALLBACK memio_Send(PRFileDesc *fd, const void *buf, PRInt32 len, - PRIntn flags, PRIntervalTime timeout) -{ - struct PRFilePrivate *secret; - struct memio_buffer *mb; - int rv; - - secret = fd->secret; - mb = &secret->writebuf; - PR_ASSERT(mb->bufsize); - - /* Note that the read error state is not reported, because it cannot be - * reported until all buffered data has been read. If there is an error - * with the next layer, attempting to call Send again will report the - * error appropriately. - */ - if (mb->last_err) { - PR_SetError(mb->last_err, 0); - return -1; - } - rv = memio_buffer_put(mb, buf, len); - if (rv == 0) { - PR_SetError(PR_WOULD_BLOCK_ERROR, 0); - return -1; - } - return rv; -} - -static int PR_CALLBACK memio_Write(PRFileDesc *fd, const void *buf, PRInt32 len) -{ - /* append bytes to buffer */ - return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT); -} - -static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) -{ - /* TODO: fail if memio_SetPeerName has not been called */ - struct PRFilePrivate *secret = fd->secret; - *addr = secret->peername; - return PR_SUCCESS; -} - -static PRStatus memio_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) -{ - /* - * Even in the original version for real tcp sockets, - * PR_SockOpt_Nonblocking is a special case that does not - * translate to a getsockopt() call - */ - if (PR_SockOpt_Nonblocking == data->option) { - data->value.non_blocking = PR_TRUE; - return PR_SUCCESS; - } - PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); - return PR_FAILURE; -} - -/*--------------- private memio data -----------------------*/ - -/* - * Implement just the bare minimum number of methods needed to make ssl happy. - * - * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls - * PR_GetSocketOption, so we have to provide an implementation of - * PR_GetSocketOption that just says "I'm nonblocking". - */ - -static struct PRIOMethods memio_layer_methods = { - PR_DESC_LAYERED, - memio_Close, - memio_Read, - memio_Write, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - memio_Shutdown, - memio_Recv, - memio_Send, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - memio_GetPeerName, - NULL, - NULL, - memio_GetSocketOption, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER; - -static PRStatus memio_InitializeLayerName(void) -{ - memio_identity = PR_GetUniqueIdentity("memio"); - return PR_SUCCESS; -} - -/*--------------- public memio functions -----------------------*/ - -PRFileDesc *memio_CreateIOLayer(int readbufsize, int writebufsize) -{ - PRFileDesc *fd; - struct PRFilePrivate *secret; - static PRCallOnceType once; - - PR_CallOnce(&once, memio_InitializeLayerName); - - fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods); - secret = malloc(sizeof(struct PRFilePrivate)); - memset(secret, 0, sizeof(*secret)); - - memio_buffer_new(&secret->readbuf, readbufsize); - memio_buffer_new(&secret->writebuf, writebufsize); - fd->secret = secret; - return fd; -} - -void memio_SetPeerName(PRFileDesc *fd, const PRNetAddr *peername) -{ - PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity); - struct PRFilePrivate *secret = memiofd->secret; - secret->peername = *peername; -} - -memio_Private *memio_GetSecret(PRFileDesc *fd) -{ - PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity); - struct PRFilePrivate *secret = memiofd->secret; - return (memio_Private *)secret; -} - -int memio_GetReadRequest(memio_Private *secret) -{ - return ((PRFilePrivate *)secret)->read_requested; -} - -int memio_GetReadParams(memio_Private *secret, char **buf) -{ - struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf; - PR_ASSERT(mb->bufsize); - - *buf = &mb->buf[mb->tail]; - return memio_buffer_unused_contiguous(mb); -} - -int memio_GetReadableBufferSize(memio_Private *secret) -{ - struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf; - PR_ASSERT(mb->bufsize); - - return memio_buffer_used_contiguous(mb); -} - -void memio_PutReadResult(memio_Private *secret, int bytes_read) -{ - struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf; - PR_ASSERT(mb->bufsize); - - if (bytes_read > 0) { - mb->tail += bytes_read; - if (mb->tail == mb->bufsize) - mb->tail = 0; - } else if (bytes_read == 0) { - /* Record EOF condition and report to caller when buffer runs dry */ - ((PRFilePrivate *)secret)->eof = PR_TRUE; - } else /* if (bytes_read < 0) */ { - mb->last_err = bytes_read; - } - - /* Clear read_requested now that the read has been satisfied. */ - ((PRFilePrivate *)secret)->read_requested = 0; -} - -int memio_GetWriteParams(memio_Private *secret, - const char **buf1, unsigned int *len1, - const char **buf2, unsigned int *len2) -{ - struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf; - PR_ASSERT(mb->bufsize); - - if (mb->last_err) - return mb->last_err; - - *buf1 = &mb->buf[mb->head]; - *len1 = memio_buffer_used_contiguous(mb); - *buf2 = mb->buf; - *len2 = memio_buffer_wrapped_bytes(mb); - return 0; -} - -void memio_PutWriteResult(memio_Private *secret, int bytes_written) -{ - struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf; - PR_ASSERT(mb->bufsize); - - if (bytes_written > 0) { - mb->head += bytes_written; - if (mb->head >= mb->bufsize) - mb->head -= mb->bufsize; - } else if (bytes_written < 0) { - mb->last_err = bytes_written; - } -} - -/*--------------- private memio_buffer self-test -----------------*/ - -/* Even a trivial unit test is very helpful when doing circular buffers. */ -/*#define TRIVIAL_SELF_TEST*/ -#ifdef TRIVIAL_SELF_TEST -#include <stdio.h> - -#define TEST_BUFLEN 7 - -#define CHECKEQ(a, b) { \ - if ((a) != (b)) { \ - printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \ - exit(1); \ - } \ -} - -int main() -{ - struct memio_buffer mb; - char buf[100]; - int i; - - memio_buffer_new(&mb, TEST_BUFLEN); - - CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1); - CHECKEQ(memio_buffer_used_contiguous(&mb), 0); - - CHECKEQ(memio_buffer_put(&mb, "howdy", 5), 5); - - CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5); - CHECKEQ(memio_buffer_used_contiguous(&mb), 5); - CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); - - CHECKEQ(memio_buffer_put(&mb, "!", 1), 1); - - CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); - CHECKEQ(memio_buffer_used_contiguous(&mb), 6); - CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); - - CHECKEQ(memio_buffer_get(&mb, buf, 6), 6); - CHECKEQ(memcmp(buf, "howdy!", 6), 0); - - CHECKEQ(memio_buffer_unused_contiguous(&mb), 1); - CHECKEQ(memio_buffer_used_contiguous(&mb), 0); - - CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5); - - CHECKEQ(memio_buffer_used_contiguous(&mb), 1); - CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4); - CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5); - - CHECKEQ(memio_buffer_put(&mb, "5", 1), 1); - - CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); - CHECKEQ(memio_buffer_used_contiguous(&mb), 1); - - /* TODO: add more cases */ - - printf("Test passed\n"); - exit(0); -} - -#endif
diff --git a/net/base/nss_memio.h b/net/base/nss_memio.h deleted file mode 100644 index b2b873bd..0000000 --- a/net/base/nss_memio.h +++ /dev/null
@@ -1,102 +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. -// Written in NSPR style to also be suitable for adding to the NSS demo suite - -#ifndef __MEMIO_H -#define __MEMIO_H - -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#include "prio.h" - -/* Opaque structure. Really just a more typesafe alias for PRFilePrivate. */ -struct memio_Private; -typedef struct memio_Private memio_Private; - -/*---------------------------------------------------------------------- - NSPR I/O layer that terminates in a pair of circular buffers - rather than talking to the real network. - To use this with NSS: - 1) call memio_CreateIOLayer to create a fake NSPR socket - 2) call SSL_ImportFD to ssl-ify the socket - 3) Do your own networking calls to set up a TCP connection - 4) call memio_SetPeerName to tell NSS about the other end of the connection - 5) While at the same time doing plaintext nonblocking NSPR I/O as - usual to the nspr file descriptor returned by SSL_ImportFD, - your app must shuttle encrypted data between - the real network and memio's network buffers. - memio_GetReadParams/memio_PutReadResult - are the hooks you need to pump data into memio's input buffer, - and memio_GetWriteParams/memio_PutWriteResult - are the hooks you need to pump data out of memio's output buffer. -----------------------------------------------------------------------*/ - -/* Create the I/O layer and its two circular buffers. */ -PRFileDesc *memio_CreateIOLayer(int readbufsize, int writebufsize); - -/* Must call before trying to make an ssl connection */ -void memio_SetPeerName(PRFileDesc *fd, const PRNetAddr *peername); - -/* Return a private pointer needed by the following - * four functions. (We could have passed a PRFileDesc to - * them, but that would be slower. Better for the caller - * to grab the pointer once and cache it. - * This may be a premature optimization.) - */ -memio_Private *memio_GetSecret(PRFileDesc *fd); - -/* Ask memio how many bytes were requested by a higher layer if the - * last attempt to read data resulted in PR_WOULD_BLOCK_ERROR, due to the - * transport buffer being empty. If the last attempt to read data from the - * memio did not result in PR_WOULD_BLOCK_ERROR, returns 0. - */ -int memio_GetReadRequest(memio_Private *secret); - -/* Ask memio where to put bytes from the network, and how many it can handle. - * Returns bytes available to write, or 0 if none available. - * Puts current buffer position into *buf. - */ -int memio_GetReadParams(memio_Private *secret, char **buf); - -/* Ask memio how many bytes are contained in the internal buffer. - * Returns bytes available to read, or 0 if none available. - */ -int memio_GetReadableBufferSize(memio_Private *secret); - -/* Tell memio how many bytes were read from the network. - * If bytes_read is 0, causes EOF to be reported to - * NSS after it reads the last byte from the circular buffer. - * If bytes_read is < 0, it is treated as an NSPR error code. - * See nspr/pr/src/md/unix/unix_errors.c for how to - * map from Unix errors to NSPR error codes. - * On EWOULDBLOCK or the equivalent, don't call this function. - */ -void memio_PutReadResult(memio_Private *secret, int bytes_read); - -/* Ask memio what data it has to send to the network. - * If there was previous a write error, the NSPR error code is returned. - * Otherwise, it returns 0 and provides up to two buffers of data by - * writing the positions and lengths into |buf1|, |len1| and |buf2|, |len2|. - */ -int memio_GetWriteParams(memio_Private *secret, - const char **buf1, unsigned int *len1, - const char **buf2, unsigned int *len2); - -/* Tell memio how many bytes were sent to the network. - * If bytes_written is < 0, it is treated as an NSPR error code. - * See nspr/pr/src/md/unix/unix_errors.c for how to - * map from Unix errors to NSPR error codes. - * On EWOULDBLOCK or the equivalent, don't call this function. - */ -void memio_PutWriteResult(memio_Private *secret, int bytes_written); - -#ifdef __cplusplus -} -#endif - -#endif
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc index 9c8267de..49a170d 100644 --- a/net/cert/cert_verify_proc.cc +++ b/net/cert/cert_verify_proc.cc
@@ -26,7 +26,7 @@ #include "net/cert/x509_certificate.h" #include "url/url_canon.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include "net/cert/cert_verify_proc_nss.h" #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) #include "net/cert/cert_verify_proc_openssl.h" @@ -205,7 +205,7 @@ // static CertVerifyProc* CertVerifyProc::CreateDefault() { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) return new CertVerifyProcNSS(); #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) return new CertVerifyProcOpenSSL();
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc index 6d01ef6..c7cf84d 100644 --- a/net/cert/cert_verify_proc_unittest.cc +++ b/net/cert/cert_verify_proc_unittest.cc
@@ -103,7 +103,7 @@ // the verified certificate chain and detect known roots. if (base::android::BuildInfo::GetInstance()->sdk_int() < 17) return false; -#elif defined(OS_IOS) && defined(USE_OPENSSL) +#elif defined(OS_IOS) // iOS does not expose the APIs necessary to get the known system roots. return false; #endif @@ -224,7 +224,7 @@ NULL, empty_cert_list_, &verify_result); -#if defined(USE_NSS_VERIFIER) || defined(OS_ANDROID) +#if defined(USE_NSS_CERTS) || defined(OS_ANDROID) EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error); #elif defined(OS_IOS) && TARGET_IPHONE_SIMULATOR // iOS returns a ERR_CERT_INVALID error on the simulator, while returning @@ -238,7 +238,7 @@ // Either the system crypto library should correctly report a certificate // name mismatch, or our certificate blacklist should cause us to report an // invalid certificate. -#if defined(USE_NSS_VERIFIER) || defined(OS_WIN) +#if defined(USE_NSS_CERTS) || defined(OS_WIN) EXPECT_TRUE(verify_result.cert_status & (CERT_STATUS_COMMON_NAME_INVALID | CERT_STATUS_INVALID)); #endif @@ -1133,7 +1133,7 @@ EXPECT_FALSE(verify_result.is_issued_by_known_root); } -#if defined(USE_NSS_VERIFIER) || defined(OS_WIN) || \ +#if defined(USE_NSS_CERTS) || defined(OS_WIN) || \ (defined(OS_MACOSX) && !defined(OS_IOS)) // Test that CRLSets are effective in making a certificate appear to be // revoked.
diff --git a/net/cert/ct_log_verifier.h b/net/cert/ct_log_verifier.h index 9f50c142..fa5ba24 100644 --- a/net/cert/ct_log_verifier.h +++ b/net/cert/ct_log_verifier.h
@@ -16,11 +16,7 @@ // Forward declare the crypto types to avoid having to include the full // headers. -#if defined(USE_OPENSSL) typedef struct evp_pkey_st EVP_PKEY; -#else -typedef struct SECKEYPublicKeyStr SECKEYPublicKey; -#endif namespace net { @@ -98,11 +94,7 @@ ct::DigitallySigned::HashAlgorithm hash_algorithm_; ct::DigitallySigned::SignatureAlgorithm signature_algorithm_; -#if defined(USE_OPENSSL) EVP_PKEY* public_key_; -#else - SECKEYPublicKey* public_key_; -#endif }; } // namespace net
diff --git a/net/cert/ct_log_verifier_nss.cc b/net/cert/ct_log_verifier_nss.cc deleted file mode 100644 index fec7dc8..0000000 --- a/net/cert/ct_log_verifier_nss.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright 2013 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 "net/cert/ct_log_verifier.h" - -#include <cryptohi.h> -#include <keyhi.h> -#include <nss.h> -#include <pk11pub.h> -#include <secitem.h> -#include <secoid.h> - -#include "base/logging.h" -#include "crypto/nss_util.h" -#include "crypto/sha2.h" -#include "net/cert/signed_tree_head.h" - -namespace net { - -namespace { - -SECOidTag GetNSSSigAlg(ct::DigitallySigned::SignatureAlgorithm alg) { - switch (alg) { - case ct::DigitallySigned::SIG_ALGO_RSA: - return SEC_OID_PKCS1_RSA_ENCRYPTION; - case ct::DigitallySigned::SIG_ALGO_DSA: - return SEC_OID_ANSIX9_DSA_SIGNATURE; - case ct::DigitallySigned::SIG_ALGO_ECDSA: - return SEC_OID_ANSIX962_EC_PUBLIC_KEY; - case ct::DigitallySigned::SIG_ALGO_ANONYMOUS: - default: - NOTREACHED(); - return SEC_OID_UNKNOWN; - } -} - -SECOidTag GetNSSHashAlg(ct::DigitallySigned::HashAlgorithm alg) { - switch (alg) { - case ct::DigitallySigned::HASH_ALGO_MD5: - return SEC_OID_MD5; - case ct::DigitallySigned::HASH_ALGO_SHA1: - return SEC_OID_SHA1; - case ct::DigitallySigned::HASH_ALGO_SHA224: - return SEC_OID_SHA224; - case ct::DigitallySigned::HASH_ALGO_SHA256: - return SEC_OID_SHA256; - case ct::DigitallySigned::HASH_ALGO_SHA384: - return SEC_OID_SHA384; - case ct::DigitallySigned::HASH_ALGO_SHA512: - return SEC_OID_SHA512; - case ct::DigitallySigned::HASH_ALGO_NONE: - default: - NOTREACHED(); - return SEC_OID_UNKNOWN; - } -} - -} // namespace - -CTLogVerifier::~CTLogVerifier() { - if (public_key_) - SECKEY_DestroyPublicKey(public_key_); -} - -bool CTLogVerifier::Init(const base::StringPiece& public_key) { - SECItem key_data; - - crypto::EnsureNSSInit(); - - key_data.data = reinterpret_cast<unsigned char*>( - const_cast<char*>(public_key.data())); - key_data.len = public_key.size(); - - CERTSubjectPublicKeyInfo* public_key_info = - SECKEY_DecodeDERSubjectPublicKeyInfo(&key_data); - if (!public_key_info) { - DVLOG(1) << "Failed decoding public key."; - return false; - } - - public_key_ = SECKEY_ExtractPublicKey(public_key_info); - SECKEY_DestroySubjectPublicKeyInfo(public_key_info); - - if (!public_key_) { - DVLOG(1) << "Failed extracting public key."; - return false; - } - - key_id_ = crypto::SHA256HashString(public_key); - - // Right now, only RSASSA-PKCS1v15 with SHA-256 and ECDSA with SHA-256 are - // supported. - switch (SECKEY_GetPublicKeyType(public_key_)) { - case rsaKey: - hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256; - signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_RSA; - break; - case ecKey: - hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256; - signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_ECDSA; - break; - default: - DVLOG(1) << "Unsupported key type: " - << SECKEY_GetPublicKeyType(public_key_); - return false; - } - - // Extra sanity check: Require RSA keys of at least 2048 bits. - if (signature_algorithm_ == ct::DigitallySigned::SIG_ALGO_RSA && - SECKEY_PublicKeyStrengthInBits(public_key_) < 2048) { - DVLOG(1) << "Too small a public key."; - return false; - } - - return true; -} - -bool CTLogVerifier::VerifySignature(const base::StringPiece& data_to_sign, - const base::StringPiece& signature) const { - SECItem sig_data; - sig_data.data = reinterpret_cast<unsigned char*>(const_cast<char*>( - signature.data())); - sig_data.len = signature.size(); - - SECStatus rv = VFY_VerifyDataDirect( - reinterpret_cast<const unsigned char*>(data_to_sign.data()), - data_to_sign.size(), public_key_, &sig_data, - GetNSSSigAlg(signature_algorithm_), GetNSSHashAlg(hash_algorithm_), - NULL, NULL); - DVLOG(1) << "Signature verification result: " << (rv == SECSuccess); - return rv == SECSuccess; -} - -} // namespace net
diff --git a/net/cert/ct_objects_extractor_nss.cc b/net/cert/ct_objects_extractor_nss.cc deleted file mode 100644 index 76a3be51..0000000 --- a/net/cert/ct_objects_extractor_nss.cc +++ /dev/null
@@ -1,619 +0,0 @@ -// Copyright 2013 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 "net/cert/ct_objects_extractor.h" - -#include <cert.h> -#include <secasn1.h> -#include <secitem.h> -#include <secoid.h> - -#include "base/lazy_instance.h" -#include "base/macros.h" -#include "base/sha1.h" -#include "crypto/scoped_nss_types.h" -#include "crypto/sha2.h" -#include "net/cert/asn1_util.h" -#include "net/cert/scoped_nss_types.h" -#include "net/cert/signed_certificate_timestamp.h" -#include "net/der/input.h" -#include "net/der/parser.h" - -namespace net { - -namespace ct { - -namespace { - -// NSS black magic to get the address of externally defined template at runtime. -SEC_ASN1_MKSUB(SEC_IntegerTemplate) -SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) -SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate) -SEC_ASN1_MKSUB(CERT_SequenceOfCertExtensionTemplate) - -// Wrapper class to convert a X509Certificate::OSCertHandle directly -// into a CERTCertificate* usable with other NSS functions. This is used for -// platforms where X509Certificate::OSCertHandle refers to a different type -// than a CERTCertificate*. -struct NSSCertWrapper { - explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle); - ~NSSCertWrapper() {} - - ScopedCERTCertificate cert; -}; - -NSSCertWrapper::NSSCertWrapper(X509Certificate::OSCertHandle cert_handle) { -#if defined(USE_NSS_CERTS) - cert.reset(CERT_DupCertificate(cert_handle)); -#else - SECItem der_cert; - std::string der_data; - if (!X509Certificate::GetDEREncoded(cert_handle, &der_data)) - return; - der_cert.data = - reinterpret_cast<unsigned char*>(const_cast<char*>(der_data.data())); - der_cert.len = der_data.size(); - - // Note: CERT_NewTempCertificate may return NULL if the certificate - // shares a serial number with another cert issued by the same CA, - // which is not supposed to happen. - cert.reset(CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE)); -#endif - DCHECK(cert.get() != NULL); -} - -// The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of -// RFC6962. -const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, - 0xD6, 0x79, 0x02, 0x04, 0x02}; -const char kEmbeddedSCTDescription[] = - "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp " - "List"; - -// The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for -// X.509v3 Certificate Transparency Signed Certificate Timestamp List, see -// Section 3.3 of RFC6962. -const unsigned char kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, - 0xD6, 0x79, 0x02, 0x04, 0x05}; - -const SECItem kOCSPExtensionOidItem = { - siBuffer, const_cast<unsigned char*>(kOCSPExtensionOid), - sizeof(kOCSPExtensionOid) -}; - -// id-ad-ocsp: 1.3.6.1.5.5.7.48.1.1 -const unsigned char kBasicOCSPResponseOid[] = {0x2B, 0x06, 0x01, 0x05, 0x05, - 0x07, 0x30, 0x01, 0x01}; - -const SECItem kBasicOCSPResponseOidItem = { - siBuffer, const_cast<unsigned char*>(kBasicOCSPResponseOid), - sizeof(kBasicOCSPResponseOid) -}; - - -// Initializes the necessary NSS internals for use with Certificate -// Transparency. -class CTInitSingleton { - public: - SECOidTag embedded_oid() const { return embedded_oid_; } - - private: - friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>; - - CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) { - embedded_oid_ = RegisterOid( - kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), kEmbeddedSCTDescription); - } - - ~CTInitSingleton() {} - - SECOidTag RegisterOid(const unsigned char* oid, - unsigned int oid_len, - const char* description) { - SECOidData oid_data; - oid_data.oid.len = oid_len; - oid_data.oid.data = const_cast<unsigned char*>(oid); - oid_data.offset = SEC_OID_UNKNOWN; - oid_data.desc = description; - oid_data.mechanism = CKM_INVALID_MECHANISM; - // Setting this to SUPPORTED_CERT_EXTENSION ensures that if a certificate - // contains this extension with the critical bit set, NSS will not reject - // it. However, because verification of this extension happens after NSS, - // it is currently left as INVALID_CERT_EXTENSION. - oid_data.supportedExtension = INVALID_CERT_EXTENSION; - - SECOidTag result = SECOID_AddEntry(&oid_data); - CHECK_NE(SEC_OID_UNKNOWN, result); - - return result; - } - - SECOidTag embedded_oid_; - - DISALLOW_COPY_AND_ASSIGN(CTInitSingleton); -}; - -base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton = - LAZY_INSTANCE_INITIALIZER; - -// Obtains the data for an X.509v3 certificate extension identified by |oid| -// and encoded as an OCTET STRING. Returns true if the extension was found in -// the certificate, updating |ext_data| to be the extension data after removing -// the DER encoding of OCTET STRING. -bool GetCertOctetStringExtension(CERTCertificate* cert, - SECOidTag oid, - std::string* extension_data) { - SECItem extension; - SECStatus rv = CERT_FindCertExtension(cert, oid, &extension); - if (rv != SECSuccess) - return false; - - der::Parser parser(der::Input(extension.data, extension.len)); - der::Input parsed_extension; - if (!parser.ReadTag(der::kOctetString, &parsed_extension) || - parser.HasMore()) { // Decoding failure or raw data left - rv = SECFailure; - } else { - *extension_data = parsed_extension.AsString(); - } - - SECITEM_FreeItem(&extension, PR_FALSE); - return rv == SECSuccess; -} - -// NSS offers CERT_FindCertExtension for certificates, but that only accepts -// CERTCertificate* inputs, so the method below extracts the SCT extension -// directly from the CERTCertExtension** of an OCSP response. -// -// Obtains the data for an OCSP extension identified by kOCSPExtensionOidItem -// and encoded as an OCTET STRING. Returns true if the extension was found in -// |extensions|, updating |extension_data| to be the extension data after -// removing the DER encoding of OCTET STRING. -bool GetSCTListFromOCSPExtension(PLArenaPool* arena, - const CERTCertExtension* const* extensions, - std::string* extension_data) { - if (!extensions) - return false; - - const CERTCertExtension* match = NULL; - - for (const CERTCertExtension* const* exts = extensions; *exts; ++exts) { - const CERTCertExtension* ext = *exts; - if (SECITEM_ItemsAreEqual(&kOCSPExtensionOidItem, &ext->id)) { - match = ext; - break; - } - } - - if (!match) - return false; - - SECItem contents; - // SEC_QuickDERDecodeItem sets |contents| to point to |match|, so it is not - // necessary to free the contents of |contents|. - SECStatus rv = SEC_QuickDERDecodeItem(arena, &contents, - SEC_ASN1_GET(SEC_OctetStringTemplate), - &match->value); - if (rv != SECSuccess) - return false; - - base::StringPiece parsed_data(reinterpret_cast<char*>(contents.data), - contents.len); - parsed_data.CopyToString(extension_data); - return true; -} - -// Given a |cert|, extract the TBSCertificate from this certificate, also -// removing the X.509 extension with OID 1.3.6.1.4.1.11129.2.4.2 (that is, -// the embedded SCT) -bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert, - std::string* to_be_signed) { - SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid()); - if (!oid) - return false; - - // This is a giant hack, due to the fact that NSS does not expose a good API - // for simply removing certificate fields from existing certificates. - CERTCertificate temp_cert; - temp_cert = *cert; - temp_cert.extensions = NULL; - - // Strip out the embedded SCT OID from the new certificate by directly - // mutating the extensions in place. - std::vector<CERTCertExtension*> new_extensions; - if (cert->extensions) { - for (CERTCertExtension** exts = cert->extensions; *exts; ++exts) { - CERTCertExtension* ext = *exts; - SECComparison result = SECITEM_CompareItem(&oid->oid, &ext->id); - if (result != SECEqual) - new_extensions.push_back(ext); - } - } - if (!new_extensions.empty()) { - new_extensions.push_back(NULL); - temp_cert.extensions = &new_extensions[0]; - } - - crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - - SECItem tbs_data; - tbs_data.len = 0; - tbs_data.data = NULL; - void* result = SEC_ASN1EncodeItem(arena.get(), - &tbs_data, - &temp_cert, - SEC_ASN1_GET(CERT_CertificateTemplate)); - if (!result) - return false; - - to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len); - return true; -} - -// The following code is adapted from the NSS OCSP module, in order to expose -// the internal structure of an OCSP response. - -// ResponseBytes ::= SEQUENCE { -// responseType OBJECT IDENTIFIER, -// response OCTET STRING } -struct ResponseBytes { - SECItem response_type; - SECItem der_response; -}; - -const SEC_ASN1Template kResponseBytesTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseBytes) }, - { SEC_ASN1_OBJECT_ID, offsetof(ResponseBytes, response_type) }, - { SEC_ASN1_OCTET_STRING, offsetof(ResponseBytes, der_response) }, - { 0 } -}; - -// OCSPResponse ::= SEQUENCE { -// responseStatus OCSPResponseStatus, -// responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } -struct OCSPResponse { - SECItem response_status; - // This indirection is needed because |response_bytes| is an optional - // component and we need a way to determine if it is missing. - ResponseBytes* response_bytes; -}; - -const SEC_ASN1Template kPointerToResponseBytesTemplate[] = { - { SEC_ASN1_POINTER, 0, kResponseBytesTemplate } -}; - -const SEC_ASN1Template kOCSPResponseTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OCSPResponse) }, - { SEC_ASN1_ENUMERATED, offsetof(OCSPResponse, response_status) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | - SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(OCSPResponse, response_bytes), - kPointerToResponseBytesTemplate }, - { 0 } -}; - -// CertID ::= SEQUENCE { -// hashAlgorithm AlgorithmIdentifier, -// issuerNameHash OCTET STRING, -- Hash of Issuer's DN -// issuerKeyHash OCTET STRING, -- Hash of Issuers public key -// serialNumber CertificateSerialNumber } -struct CertID { - SECAlgorithmID hash_algorithm; - SECItem issuer_name_hash; - SECItem issuer_key_hash; - SECItem serial_number; -}; - -const SEC_ASN1Template kCertIDTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CertID) }, - { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CertID, hash_algorithm), - SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, - { SEC_ASN1_OCTET_STRING, offsetof(CertID, issuer_name_hash) }, - { SEC_ASN1_OCTET_STRING, offsetof(CertID, issuer_key_hash) }, - { SEC_ASN1_INTEGER, offsetof(CertID, serial_number) }, - { 0 } -}; - -// SingleResponse ::= SEQUENCE { -// certID CertID, -// certStatus CertStatus, -// thisUpdate GeneralizedTime, -// nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, -// singleExtensions [1] EXPLICIT Extensions OPTIONAL } -struct SingleResponse { - CertID cert_id; - // The following three fields are not used. - SECItem der_cert_status; - SECItem this_update; - SECItem next_update; - CERTCertExtension** single_extensions; -}; - -const SEC_ASN1Template kSingleResponseTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SingleResponse) }, - { SEC_ASN1_INLINE, offsetof(SingleResponse, cert_id), kCertIDTemplate }, - // Really a CHOICE but we make it an ANY because we don't care about the - // contents of this field. - // TODO(ekasper): use SEC_ASN1_CHOICE. - { SEC_ASN1_ANY, offsetof(SingleResponse, der_cert_status) }, - { SEC_ASN1_GENERALIZED_TIME, offsetof(SingleResponse, this_update) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, - offsetof(SingleResponse, next_update), - SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | - SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, - offsetof(SingleResponse, single_extensions), - SEC_ASN1_SUB(CERT_SequenceOfCertExtensionTemplate) }, - { 0 } -}; - -// ResponseData ::= SEQUENCE { -// version [0] EXPLICIT Version DEFAULT v1, -// responderID ResponderID, -// producedAt GeneralizedTime, -// responses SEQUENCE OF SingleResponse, -// responseExtensions [1] EXPLICIT Extensions OPTIONAL } -struct ResponseData { - // The first three fields are not used. - SECItem version; - SECItem der_responder_id; - SECItem produced_at; - SingleResponse** single_responses; - // Skip extensions. -}; - -const SEC_ASN1Template kResponseDataTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseData) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | - SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, - offsetof(ResponseData, version), SEC_ASN1_SUB(SEC_IntegerTemplate) }, - // Really a CHOICE but we make it an ANY because we don't care about the - // contents of this field. - // TODO(ekasper): use SEC_ASN1_CHOICE. - { SEC_ASN1_ANY, offsetof(ResponseData, der_responder_id) }, - { SEC_ASN1_GENERALIZED_TIME, offsetof(ResponseData, produced_at) }, - { SEC_ASN1_SEQUENCE_OF, offsetof(ResponseData, single_responses), - kSingleResponseTemplate }, - { SEC_ASN1_SKIP_REST }, - { 0 } -}; - -// BasicOCSPResponse ::= SEQUENCE { -// tbsResponseData ResponseData, -// signatureAlgorithm AlgorithmIdentifier, -// signature BIT STRING, -// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } -struct BasicOCSPResponse { - ResponseData tbs_response_data; - // We do not care about the rest. -}; - -const SEC_ASN1Template kBasicOCSPResponseTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(BasicOCSPResponse) }, - { SEC_ASN1_INLINE, offsetof(BasicOCSPResponse, tbs_response_data), - kResponseDataTemplate }, - { SEC_ASN1_SKIP_REST }, - { 0 } -}; - -bool StringEqualToSECItem(const std::string& value1, const SECItem& value2) { - if (value1.size() != value2.len) - return false; - return memcmp(value1.data(), value2.data, value2.len) == 0; -} - -// TODO(ekasper): also use the issuer name hash in matching. -bool CertIDMatches(const CertID& cert_id, - const std::string& serial_number, - const std::string& issuer_key_sha1_hash, - const std::string& issuer_key_sha256_hash) { - if (!StringEqualToSECItem(serial_number, cert_id.serial_number)) - return false; - - SECOidTag hash_alg = SECOID_FindOIDTag(&cert_id.hash_algorithm.algorithm); - switch (hash_alg) { - case SEC_OID_SHA1: - return StringEqualToSECItem(issuer_key_sha1_hash, - cert_id.issuer_key_hash); - case SEC_OID_SHA256: - return StringEqualToSECItem(issuer_key_sha256_hash, - cert_id.issuer_key_hash); - default: - return false; - } -} - -} // namespace - -bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, - std::string* sct_list) { - DCHECK(cert); - - NSSCertWrapper leaf_cert(cert); - if (!leaf_cert.cert) - return false; - - return GetCertOctetStringExtension(leaf_cert.cert.get(), - g_ct_singleton.Get().embedded_oid(), - sct_list); -} - -bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, - X509Certificate::OSCertHandle issuer, - LogEntry* result) { - DCHECK(leaf); - DCHECK(issuer); - - NSSCertWrapper leaf_cert(leaf); - NSSCertWrapper issuer_cert(issuer); - - result->Reset(); - // XXX(rsleevi): This check may be overkill, since we should be able to - // generate precerts for certs without the extension. For now, just a sanity - // check to match the reference implementation. - SECItem extension; - SECStatus rv = CERT_FindCertExtension( - leaf_cert.cert.get(), g_ct_singleton.Get().embedded_oid(), &extension); - if (rv != SECSuccess) - return false; - SECITEM_FreeItem(&extension, PR_FALSE); - - std::string to_be_signed; - if (!ExtractTBSCertWithoutSCTs(leaf_cert.cert.get(), &to_be_signed)) - return false; - - if (!issuer_cert.cert) { - // This can happen when the issuer and leaf certs share the same serial - // number and are from the same CA, which should never be the case - // (but happened with bad test certs). - VLOG(1) << "Issuer cert is null, cannot generate Precert entry."; - return false; - } - - SECKEYPublicKey* issuer_pub_key = - SECKEY_ExtractPublicKey(&(issuer_cert.cert->subjectPublicKeyInfo)); - if (!issuer_pub_key) { - VLOG(1) << "Could not extract issuer public key, " - << "cannot generate Precert entry."; - return false; - } - - SECItem* encoded_issuer_pubKey = - SECKEY_EncodeDERSubjectPublicKeyInfo(issuer_pub_key); - if (!encoded_issuer_pubKey) { - SECKEY_DestroyPublicKey(issuer_pub_key); - return false; - } - - result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT; - result->tbs_certificate.swap(to_be_signed); - - crypto::SHA256HashString( - base::StringPiece(reinterpret_cast<char*>(encoded_issuer_pubKey->data), - encoded_issuer_pubKey->len), - result->issuer_key_hash.data, - sizeof(result->issuer_key_hash.data)); - - SECITEM_FreeItem(encoded_issuer_pubKey, PR_TRUE); - SECKEY_DestroyPublicKey(issuer_pub_key); - - return true; -} - -bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) { - DCHECK(leaf); - - std::string encoded; - if (!X509Certificate::GetDEREncoded(leaf, &encoded)) - return false; - - result->Reset(); - result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509; - result->leaf_certificate.swap(encoded); - return true; -} - -bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer, - const std::string& cert_serial_number, - const std::string& ocsp_response, - std::string* sct_list) { - DCHECK(issuer); - - // Any OCSP response is unlikely to be even close to 2^24 bytes; further, CT - // only uses stapled OCSP responses which have this limit imposed by the TLS - // protocol. - if (ocsp_response.size() > 0xffffff) - return false; - - crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - - OCSPResponse response; - memset(&response, 0, sizeof(response)); - - SECItem src = { siBuffer, - reinterpret_cast<unsigned char*>(const_cast<char*>( - ocsp_response.data())), - static_cast<unsigned int>(ocsp_response.size()) }; - - // |response| will point directly into |src|, so it's not necessary to - // free the |response| contents, but they may only be used while |src| - // is valid (i.e., in this method). - SECStatus rv = SEC_QuickDERDecodeItem(arena.get(), &response, - kOCSPResponseTemplate, &src); - if (rv != SECSuccess) - return false; - - if (!response.response_bytes) - return false; - - if (!SECITEM_ItemsAreEqual(&kBasicOCSPResponseOidItem, - &response.response_bytes->response_type)) { - return false; - } - - BasicOCSPResponse basic_response; - memset(&basic_response, 0, sizeof(basic_response)); - - rv = SEC_QuickDERDecodeItem(arena.get(), &basic_response, - kBasicOCSPResponseTemplate, - &response.response_bytes->der_response); - if (rv != SECSuccess) - return false; - - SingleResponse** responses = - basic_response.tbs_response_data.single_responses; - if (!responses) - return false; - - std::string issuer_der; - if (!X509Certificate::GetDEREncoded(issuer, &issuer_der)) - return false; - - base::StringPiece issuer_spki; - if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki)) - return false; - - // In OCSP, only the key itself is under hash. - base::StringPiece issuer_spk; - if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk)) - return false; - - // ExtractSubjectPublicKey... does not remove the initial octet encoding the - // number of unused bits in the ASN.1 BIT STRING so we do it here. For public - // keys, the bitstring is in practice always byte-aligned. - if (issuer_spk.empty() || issuer_spk[0] != 0) - return false; - issuer_spk.remove_prefix(1); - - // NSS OCSP lib recognizes SHA1, MD5 and MD2; MD5 and MD2 are dead but - // https://bugzilla.mozilla.org/show_bug.cgi?id=663315 will add SHA-256 - // and SHA-384. - // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves - // necessary. - // TODO(ekasper): only compute the hashes on demand. - std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk); - std::string issuer_key_sha1_hash = base::SHA1HashString( - issuer_spk.as_string()); - - const SingleResponse* match = NULL; - for (const SingleResponse* const* resps = responses; *resps; ++resps) { - const SingleResponse* resp = *resps; - if (CertIDMatches(resp->cert_id, cert_serial_number, - issuer_key_sha1_hash, issuer_key_sha256_hash)) { - match = resp; - break; - } - } - - if (!match) - return false; - - return GetSCTListFromOCSPExtension(arena.get(), match->single_extensions, - sct_list); -} - -} // namespace ct - -} // namespace net
diff --git a/net/cert/ev_root_ca_metadata.cc b/net/cert/ev_root_ca_metadata.cc index a46e50a..dc2cea9 100644 --- a/net/cert/ev_root_ca_metadata.cc +++ b/net/cert/ev_root_ca_metadata.cc
@@ -4,7 +4,7 @@ #include "net/cert/ev_root_ca_metadata.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include <cert.h> #include <pkcs11n.h> #include <secerr.h> @@ -15,13 +15,13 @@ #include "base/lazy_instance.h" #include "base/logging.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include "crypto/nss_util.h" #endif namespace net { -#if defined(USE_NSS_VERIFIER) || defined(OS_WIN) +#if defined(USE_NSS_CERTS) || defined(OS_WIN) // Raw metadata. struct EVMetadata { // kMaxOIDsPerCA is the number of OIDs that we can support per root CA. At @@ -582,7 +582,7 @@ return g_ev_root_ca_metadata.Pointer(); } -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const { return policy_oids_.find(policy_oid) != policy_oids_.end(); } @@ -728,7 +728,7 @@ EVRootCAMetadata::EVRootCAMetadata() { // Constructs the object from the raw metadata in ev_root_ca_metadata. -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) crypto::EnsureNSSInit(); for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) {
diff --git a/net/cert/ev_root_ca_metadata.h b/net/cert/ev_root_ca_metadata.h index 967dcbbd..dfb14bc6 100644 --- a/net/cert/ev_root_ca_metadata.h +++ b/net/cert/ev_root_ca_metadata.h
@@ -7,7 +7,7 @@ #include "build/build_config.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include <secoidt.h> #endif @@ -31,7 +31,7 @@ // extended-validation (EV) certificates. class NET_EXPORT_PRIVATE EVRootCAMetadata { public: -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) typedef SECOidTag PolicyOID; #elif defined(OS_WIN) typedef const char* PolicyOID; @@ -39,7 +39,7 @@ static EVRootCAMetadata* GetInstance(); -#if defined(USE_NSS_VERIFIER) || defined(OS_WIN) +#if defined(USE_NSS_CERTS) || defined(OS_WIN) // Returns true if policy_oid is an EV policy OID of some root CA. bool IsEVPolicyOID(PolicyOID policy_oid) const; @@ -64,7 +64,7 @@ EVRootCAMetadata(); ~EVRootCAMetadata(); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) typedef std::map<SHA1HashValue, std::vector<PolicyOID>, SHA1HashValueLessThan> PolicyOIDMap;
diff --git a/net/cert/internal/signature_policy.cc b/net/cert/internal/signature_policy.cc index 69f22f7..c00212ac 100644 --- a/net/cert/internal/signature_policy.cc +++ b/net/cert/internal/signature_policy.cc
@@ -6,9 +6,7 @@ #include "base/logging.h" -#if defined(USE_OPENSSL) #include <openssl/obj.h> -#endif namespace net { @@ -18,14 +16,12 @@ } bool SignaturePolicy::IsAcceptableCurveForEcdsa(int curve_nid) const { -#if defined(USE_OPENSSL) switch (curve_nid) { case NID_X9_62_prime256v1: case NID_secp384r1: case NID_secp521r1: return true; } -#endif return false; }
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc index 98b0e7b..5993b9c1 100644 --- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc +++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(eroman): Because VerifySignedData() is only implemented for BoringSSL -// these tests also depend on BoringSSL. -#if defined(USE_OPENSSL) - #include "net/cert/internal/verify_certificate_chain.h" #include "net/cert/internal/parse_certificate.h" @@ -219,5 +215,3 @@ // PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy } // namespace net - -#endif // USE_OPENSSL
diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc index c997f538..b172a338 100644 --- a/net/cert/internal/verify_certificate_chain_unittest.cc +++ b/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -17,10 +17,6 @@ #include "net/der/input.h" #include "testing/gtest/include/gtest/gtest.h" -// TODO(eroman): Because VerifySignedData() is only implemented for BoringSSL -// these tests also depend on BoringSSL. -#if defined(USE_OPENSSL) - namespace net { namespace { @@ -242,5 +238,3 @@ } // namespace } // namespace net - -#endif
diff --git a/net/cert/internal/verify_signed_data.cc b/net/cert/internal/verify_signed_data.cc index eb0fd3ff..fe6aae8 100644 --- a/net/cert/internal/verify_signed_data.cc +++ b/net/cert/internal/verify_signed_data.cc
@@ -4,31 +4,6 @@ #include "net/cert/internal/verify_signed_data.h" -#include "base/logging.h" -#include "net/der/parse_values.h" - -// TODO(eroman): There is no intention to implement this for non-OpenSSL. Remove -// this branch once the migration is complete. This could have been done as a -// conditional file (_openssl.cc) in the build file instead, but that is likely -// not worth the effort at this point. - -#if !defined(USE_OPENSSL) - -namespace net { - -bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, - const der::Input& signed_data, - const der::BitString& signature_value, - const der::Input& public_key, - const SignaturePolicy* policy) { - NOTIMPLEMENTED(); - return false; -} - -} // namespace net - -#else - #include <openssl/bytestring.h> #include <openssl/digest.h> #include <openssl/ec.h> @@ -37,11 +12,13 @@ #include <openssl/rsa.h> #include "base/compiler_specific.h" +#include "base/logging.h" #include "crypto/openssl_util.h" #include "crypto/scoped_openssl_types.h" #include "net/cert/internal/signature_algorithm.h" #include "net/cert/internal/signature_policy.h" #include "net/der/input.h" +#include "net/der/parse_values.h" #include "net/der/parser.h" namespace net { @@ -312,5 +289,3 @@ } } // namespace net - -#endif
diff --git a/net/cert/internal/verify_signed_data_unittest.cc b/net/cert/internal/verify_signed_data_unittest.cc index 50586a1..ba0fab2 100644 --- a/net/cert/internal/verify_signed_data_unittest.cc +++ b/net/cert/internal/verify_signed_data_unittest.cc
@@ -15,9 +15,7 @@ #include "net/der/parser.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_OPENSSL) #include <openssl/obj.h> -#endif namespace net { @@ -39,11 +37,6 @@ void RunTestCaseUsingPolicy(VerifyResult expected_result, const char* file_name, const SignaturePolicy* policy) { -#if !defined(USE_OPENSSL) - LOG(INFO) << "Skipping test, only implemented for BoringSSL"; - return; -#endif - std::string path = std::string("net/data/verify_signed_data_unittest/") + file_name; @@ -223,10 +216,8 @@ class RejectSecp384r1Policy : public SignaturePolicy { public: bool IsAcceptableCurveForEcdsa(int curve_nid) const override { -#if defined(USE_OPENSSL) if (curve_nid == NID_secp384r1) return false; -#endif return true; } };
diff --git a/net/cert/jwk_serializer_nss.cc b/net/cert/jwk_serializer_nss.cc deleted file mode 100644 index 6059453..0000000 --- a/net/cert/jwk_serializer_nss.cc +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright 2013 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> -#include <keyhi.h> -#include <nss.h> - -#include <memory> - -#include "base/base64url.h" -#include "base/values.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" -#include "net/cert/jwk_serializer.h" - -namespace net { - -namespace JwkSerializer { - -namespace { - -bool ConvertEcPrime256v1PublicKeyInfoToJwk( - CERTSubjectPublicKeyInfo* spki, - base::DictionaryValue* public_key_jwk) { - static const int kUncompressedEncodingType = 4; - static const int kPrime256v1PublicKeyLength = 64; - // The public key value is encoded as 0x04 + 64 bytes of public key. - // NSS gives the length as the bit length. - if (spki->subjectPublicKey.len != (kPrime256v1PublicKeyLength + 1) * 8 || - spki->subjectPublicKey.data[0] != kUncompressedEncodingType) - return false; - - public_key_jwk->SetString("kty", "EC"); - public_key_jwk->SetString("crv", "P-256"); - - base::StringPiece x( - reinterpret_cast<char*>(spki->subjectPublicKey.data + 1), - kPrime256v1PublicKeyLength / 2); - std::string x_b64; - base::Base64UrlEncode(x, base::Base64UrlEncodePolicy::OMIT_PADDING, &x_b64); - public_key_jwk->SetString("x", x_b64); - - base::StringPiece y( - reinterpret_cast<char*>(spki->subjectPublicKey.data + 1 + - kPrime256v1PublicKeyLength / 2), - kPrime256v1PublicKeyLength / 2); - std::string y_b64; - base::Base64UrlEncode(y, base::Base64UrlEncodePolicy::OMIT_PADDING, &y_b64); - public_key_jwk->SetString("y", y_b64); - return true; -} - -bool ConvertEcPublicKeyInfoToJwk( - CERTSubjectPublicKeyInfo* spki, - base::DictionaryValue* public_key_jwk) { - // 1.2.840.10045.3.1.7 - // (iso.member-body.us.ansi-x9-62.ellipticCurve.primeCurve.prime256v1) - // (This includes the DER-encoded type (OID) and length: parameters can be - // anything, so the DER type isn't implied, and NSS includes it.) - static const unsigned char kPrime256v1[] = { - 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 - }; - if (spki->algorithm.parameters.len == sizeof(kPrime256v1) && - !memcmp(spki->algorithm.parameters.data, kPrime256v1, - sizeof(kPrime256v1))) { - return ConvertEcPrime256v1PublicKeyInfoToJwk(spki, public_key_jwk); - } - // TODO(juanlang): other curves - return false; -} - -typedef std::unique_ptr< - CERTSubjectPublicKeyInfo, - crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, - SECKEY_DestroySubjectPublicKeyInfo>> - ScopedCERTSubjectPublicKeyInfo; - -} // namespace - -bool ConvertSpkiFromDerToJwk( - const base::StringPiece& spki_der, - base::DictionaryValue* public_key_jwk) { - public_key_jwk->Clear(); - - crypto::EnsureNSSInit(); - - if (!NSS_IsInitialized()) - return false; - - SECItem sec_item; - sec_item.data = const_cast<unsigned char*>( - reinterpret_cast<const unsigned char*>(spki_der.data())); - sec_item.len = spki_der.size(); - ScopedCERTSubjectPublicKeyInfo spki( - SECKEY_DecodeDERSubjectPublicKeyInfo(&sec_item)); - if (!spki) - return false; - - // 1.2.840.10045.2 - // (iso.member-body.us.ansi-x9-62.id-ecPublicKey) - // (This omits the ASN.1 encoding of the type (OID) and length: the fact that - // this is an OID is already clear, and NSS omits it here.) - static const unsigned char kIdEcPublicKey[] = { - 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 - }; - bool rv = false; - if (spki->algorithm.algorithm.len == sizeof(kIdEcPublicKey) && - !memcmp(spki->algorithm.algorithm.data, kIdEcPublicKey, - sizeof(kIdEcPublicKey))) { - rv = ConvertEcPublicKeyInfoToJwk(spki.get(), public_key_jwk); - } - // TODO(juanlang): other algorithms - return rv; -} - -} // namespace JwkSerializer - -} // namespace net
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc index d39c705..2d65025 100644 --- a/net/cert/multi_threaded_cert_verifier.cc +++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -32,7 +32,7 @@ #include "net/cert/x509_certificate_net_log_param.h" #include "net/log/net_log.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include <private/pprthred.h> // PR_DetachThread #endif @@ -241,7 +241,7 @@ *error = verify_proc->Verify(cert.get(), hostname, ocsp_response, flags, crl_set.get(), additional_trust_anchors, result); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) // 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/cert/test_root_certs.h b/net/cert/test_root_certs.h index 412bbe8..1775e39 100644 --- a/net/cert/test_root_certs.h +++ b/net/cert/test_root_certs.h
@@ -11,7 +11,7 @@ #include "build/build_config.h" #include "net/base/net_export.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include <list> #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) #include <vector> @@ -67,7 +67,7 @@ #if defined(USE_NSS_CERTS) bool Contains(CERTCertificate* cert) const; -#elif defined(OS_MACOSX) && !defined(USE_NSS_VERIFIER) +#elif defined(OS_MACOSX) && !defined(USE_NSS_CERTS) CFArrayRef temporary_roots() const { return temporary_roots_; } // Modifies the root certificates of |trust_ref| to include the @@ -102,7 +102,7 @@ // Performs platform-dependent initialization. void Init(); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) // It is necessary to maintain a cache of the original certificate trust // settings, in order to restore them when Clear() is called. class TrustEntry;
diff --git a/net/cert/test_root_certs_unittest.cc b/net/cert/test_root_certs_unittest.cc index 2f449e765..6f8a380 100644 --- a/net/cert/test_root_certs_unittest.cc +++ b/net/cert/test_root_certs_unittest.cc
@@ -14,7 +14,7 @@ #include "net/test/cert_test_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include <nss.h> #endif @@ -75,7 +75,6 @@ return; } #endif - TestRootCerts* test_roots = TestRootCerts::GetInstance(); ASSERT_NE(static_cast<TestRootCerts*>(NULL), test_roots); EXPECT_TRUE(test_roots->IsEmpty());
diff --git a/net/cert/x509_certificate_ios.cc b/net/cert/x509_certificate_ios.cc index a69792a9..96ed1de 100644 --- a/net/cert/x509_certificate_ios.cc +++ b/net/cert/x509_certificate_ios.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2016 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. @@ -6,40 +6,29 @@ #include <CommonCrypto/CommonDigest.h> #include <Security/Security.h> -#include <cert.h> -#include <cryptohi.h> -#include <keyhi.h> -#include <nss.h> -#include <pk11pub.h> -#include <prerror.h> -#include <prtime.h> -#include <prtypes.h> -#include <secder.h> -#include <secerr.h> -#include <sslerr.h> -#include <memory> -#include <vector> +#include <openssl/x509.h> +#include <openssl/x509v3.h> -#include "base/logging.h" #include "base/mac/scoped_cftyperef.h" -#include "base/numerics/safe_conversions.h" #include "base/pickle.h" -#include "base/time/time.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" -#include "net/base/net_errors.h" -#include "net/cert/asn1_util.h" -#include "net/cert/cert_status_flags.h" -#include "net/cert/cert_verify_result.h" -#include "net/cert/ev_root_ca_metadata.h" -#include "net/cert/x509_util_ios.h" -#include "net/cert/x509_util_nss.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "crypto/openssl_util.h" +#include "crypto/scoped_openssl_types.h" +#include "net/base/ip_address_number.h" +#include "net/cert/x509_util_openssl.h" +#include "net/ssl/openssl_ssl_util.h" using base::ScopedCFTypeRef; namespace net { + namespace { + +using ScopedGENERAL_NAMES = + crypto::ScopedOpenSSL<GENERAL_NAMES, GENERAL_NAMES_free>; + // Returns true if a given |cert_handle| is actually a valid X.509 certificate // handle. // @@ -52,115 +41,127 @@ bool IsValidOSCertHandle(SecCertificateRef cert_handle) { ScopedCFTypeRef<CFStringRef> sanity_check( SecCertificateCopySubjectSummary(cert_handle)); - return sanity_check != NULL; -} -} // namespace - -void X509Certificate::Initialize() { - x509_util_ios::NSSCertificate nss_cert(cert_handle_); - CERTCertificate* cert_handle = nss_cert.cert_handle(); - if (cert_handle) { - x509_util::ParsePrincipal(&cert_handle->subject, &subject_); - x509_util::ParsePrincipal(&cert_handle->issuer, &issuer_); - x509_util::ParseDate(&cert_handle->validity.notBefore, &valid_start_); - x509_util::ParseDate(&cert_handle->validity.notAfter, &valid_expiry_); - serial_number_ = x509_util::ParseSerialNumber(cert_handle); - } - fingerprint_ = CalculateFingerprint(cert_handle_); - ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); + return sanity_check != nullptr; } -bool X509Certificate::IsIssuedByEncoded( - const std::vector<std::string>& valid_issuers) { - x509_util_ios::NSSCertChain nss_chain(this); - // Convert to scoped CERTName* list. - std::vector<CERTName*> issuers; - crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - if (!x509_util::GetIssuersFromEncodedList(valid_issuers, - arena.get(), - &issuers)) { - return false; - } - return x509_util::IsCertificateIssuedBy( - nss_chain.cert_chain(), issuers); -} - -void X509Certificate::GetSubjectAltName( - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addrs) const { - x509_util_ios::NSSCertificate nss_cert(cert_handle_); - CERTCertificate* cert_handle = nss_cert.cert_handle(); - if (!cert_handle) { - if (dns_names) - dns_names->clear(); - if (ip_addrs) - ip_addrs->clear(); - return; - } - x509_util::GetSubjectAltName(cert_handle, dns_names, ip_addrs); -} - -// static -bool X509Certificate::GetDEREncoded(OSCertHandle cert_handle, - std::string* encoded) { - if (!cert_handle) - return false; - ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert_handle)); - if (!der_data) - return false; - encoded->assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), - CFDataGetLength(der_data)); - return true; -} - -// static -bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, - X509Certificate::OSCertHandle b) { - DCHECK(a && b); - if (a == b) - return true; - if (CFEqual(a, b)) - return true; - ScopedCFTypeRef<CFDataRef> a_data(SecCertificateCopyData(a)); - ScopedCFTypeRef<CFDataRef> b_data(SecCertificateCopyData(b)); - return a_data && b_data && - CFDataGetLength(a_data) == CFDataGetLength(b_data) && - memcmp(CFDataGetBytePtr(a_data), CFDataGetBytePtr(b_data), - CFDataGetLength(a_data)) == 0; -} - -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, - size_t length) { - ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy( - kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), - base::checked_cast<CFIndex>(length), kCFAllocatorNull)); - if (!cert_data) - return nullptr; - OSCertHandle cert_handle = SecCertificateCreateWithData(NULL, cert_data); - if (!cert_handle) - return nullptr; - if (!IsValidOSCertHandle(cert_handle)) { - CFRelease(cert_handle); - return nullptr; - } - return cert_handle; -} - -// static -X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( +void CreateOSCertHandlesFromPKCS7Bytes( const char* data, size_t length, - Format format) { - return x509_util::CreateOSCertHandlesFromBytes(data, length, format); + X509Certificate::OSCertHandles* handles) { + crypto::EnsureOpenSSLInit(); + crypto::OpenSSLErrStackTracer err_cleaner(FROM_HERE); + + CBS der_data; + CBS_init(&der_data, reinterpret_cast<const uint8_t*>(data), length); + STACK_OF(X509)* certs = sk_X509_new_null(); + + if (PKCS7_get_certificates(certs, &der_data)) { + for (size_t i = 0; i < sk_X509_num(certs); ++i) { + X509* x509_cert = sk_X509_value(certs, i); + base::StringPiece der; + if (!x509_util::GetDER(x509_cert, &der)) + return; + handles->push_back(X509Certificate::CreateOSCertHandleFromBytes( + der.data(), der.length())); + } + } + sk_X509_pop_free(certs, X509_free); } +void ParsePrincipalValues(X509_NAME* name, + int nid, + std::vector<std::string>* fields) { + for (int index = -1; + (index = X509_NAME_get_index_by_NID(name, nid, index)) != -1;) { + std::string field; + if (!x509_util::ParsePrincipalValueByIndex(name, index, &field)) + break; + fields->push_back(field); + } +} + +void ParsePrincipal(X509Certificate::OSCertHandle os_cert, + X509_NAME* x509_name, + CertPrincipal* principal) { + if (!x509_name) + return; + + ParsePrincipalValues(x509_name, NID_streetAddress, + &principal->street_addresses); + ParsePrincipalValues(x509_name, NID_organizationName, + &principal->organization_names); + ParsePrincipalValues(x509_name, NID_organizationalUnitName, + &principal->organization_unit_names); + ParsePrincipalValues(x509_name, NID_domainComponent, + &principal->domain_components); + + x509_util::ParsePrincipalValueByNID(x509_name, NID_commonName, + &principal->common_name); + x509_util::ParsePrincipalValueByNID(x509_name, NID_localityName, + &principal->locality_name); + x509_util::ParsePrincipalValueByNID(x509_name, NID_stateOrProvinceName, + &principal->state_or_province_name); + x509_util::ParsePrincipalValueByNID(x509_name, NID_countryName, + &principal->country_name); +} + +void ParseSubjectAltName(X509Certificate::OSCertHandle os_cert, + std::vector<std::string>* dns_names, + std::vector<std::string>* ip_addresses) { + DCHECK(dns_names || ip_addresses); + ScopedX509 cert = OSCertHandleToOpenSSL(os_cert); + if (!cert.get()) + return; + int index = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1); + X509_EXTENSION* alt_name_ext = X509_get_ext(cert.get(), index); + if (!alt_name_ext) + return; + + ScopedGENERAL_NAMES alt_names( + reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(alt_name_ext))); + if (!alt_names.get()) + return; + + for (size_t i = 0; i < sk_GENERAL_NAME_num(alt_names.get()); ++i) { + const GENERAL_NAME* name = sk_GENERAL_NAME_value(alt_names.get(), i); + if (name->type == GEN_DNS && dns_names) { + const unsigned char* dns_name = ASN1_STRING_data(name->d.dNSName); + if (!dns_name) + continue; + int dns_name_len = ASN1_STRING_length(name->d.dNSName); + dns_names->push_back( + std::string(reinterpret_cast<const char*>(dns_name), dns_name_len)); + } else if (name->type == GEN_IPADD && ip_addresses) { + const unsigned char* ip_addr = name->d.iPAddress->data; + if (!ip_addr) + continue; + int ip_addr_len = name->d.iPAddress->length; + if (ip_addr_len != static_cast<int>(kIPv4AddressSize) && + ip_addr_len != static_cast<int>(kIPv6AddressSize)) { + // http://www.ietf.org/rfc/rfc3280.txt requires subjectAltName iPAddress + // to have 4 or 16 bytes, whereas in a name constraint it includes a + // net mask hence 8 or 32 bytes. Logging to help diagnose any mixup. + LOG(WARNING) << "Bad sized IP Address in cert: " << ip_addr_len; + continue; + } + ip_addresses->push_back( + std::string(reinterpret_cast<const char*>(ip_addr), ip_addr_len)); + } + } +} + +// Used to free a list of X509_NAMEs and the objects it points to. +void sk_X509_NAME_free_all(STACK_OF(X509_NAME) * sk) { + sk_X509_NAME_pop_free(sk, X509_NAME_free); +} + +} // namespace + // static X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( OSCertHandle handle) { if (!handle) - return NULL; + return nullptr; return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); } @@ -170,9 +171,37 @@ CFRelease(cert_handle); } +void X509Certificate::Initialize() { + crypto::EnsureOpenSSLInit(); + fingerprint_ = CalculateFingerprint(cert_handle_); + ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); + ScopedX509 x509_cert = OSCertHandleToOpenSSL(cert_handle_); + if (!x509_cert) + return; + ASN1_INTEGER* serial_num = X509_get_serialNumber(x509_cert.get()); + if (serial_num) { + // ASN1_INTEGERS represent the decoded number, in a format internal to + // OpenSSL. Most notably, this may have leading zeroes stripped off for + // numbers whose first byte is >= 0x80. Thus, it is necessary to + // re-encoded the integer back into DER, which is what the interface + // of X509Certificate exposes, to ensure callers get the proper (DER) + // value. + int bytes_required = i2c_ASN1_INTEGER(serial_num, nullptr); + unsigned char* buffer = reinterpret_cast<unsigned char*>( + base::WriteInto(&serial_number_, bytes_required + 1)); + int bytes_written = i2c_ASN1_INTEGER(serial_num, &buffer); + DCHECK_EQ(static_cast<size_t>(bytes_written), serial_number_.size()); + } + + ParsePrincipal(cert_handle_, X509_get_subject_name(x509_cert.get()), + &subject_); + ParsePrincipal(cert_handle_, X509_get_issuer_name(x509_cert.get()), &issuer_); + x509_util::ParseDate(X509_get_notBefore(x509_cert.get()), &valid_start_); + x509_util::ParseDate(X509_get_notAfter(x509_cert.get()), &valid_expiry_); +} + // static -SHA1HashValue X509Certificate::CalculateFingerprint( - OSCertHandle cert) { +SHA1HashValue X509Certificate::CalculateFingerprint(OSCertHandle cert) { SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); @@ -196,8 +225,8 @@ return sha256; DCHECK(CFDataGetBytePtr(cert_data)); DCHECK_NE(0, CFDataGetLength(cert_data)); - CC_SHA256( - CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), sha256.data); + CC_SHA256(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), + sha256.data); return sha256; } @@ -208,17 +237,14 @@ SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); - // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so - // we don't check their return values. CC_SHA1_CTX sha1_ctx; CC_SHA1_Init(&sha1_ctx); for (size_t i = 0; i < intermediates.size(); ++i) { - ScopedCFTypeRef<CFDataRef> - cert_data(SecCertificateCopyData(intermediates[i])); + ScopedCFTypeRef<CFDataRef> cert_data( + SecCertificateCopyData(intermediates[i])); if (!cert_data) return sha1; - CC_SHA1_Update(&sha1_ctx, - CFDataGetBytePtr(cert_data), + CC_SHA1_Update(&sha1_ctx, CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data)); } CC_SHA1_Final(sha1.data, &sha1_ctx); @@ -226,9 +252,93 @@ } // static +X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( + const char* data, + size_t length) { + ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), + base::checked_cast<CFIndex>(length), kCFAllocatorNull)); + if (!cert_data) + return nullptr; + OSCertHandle cert_handle = SecCertificateCreateWithData(nullptr, cert_data); + if (!cert_handle) + return nullptr; + if (!IsValidOSCertHandle(cert_handle)) { + CFRelease(cert_handle); + return nullptr; + } + return cert_handle; +} + +// static +X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( + const char* data, + size_t length, + Format format) { + OSCertHandles results; + + switch (format) { + case FORMAT_SINGLE_CERTIFICATE: { + OSCertHandle handle = + X509Certificate::CreateOSCertHandleFromBytes(data, length); + if (handle) + results.push_back(handle); + break; + } + case FORMAT_PKCS7: { + CreateOSCertHandlesFromPKCS7Bytes(data, length, &results); + break; + } + default: { + NOTREACHED() << "Certificate format " << format << " unimplemented"; + break; + } + } + + return results; +} + +void X509Certificate::GetSubjectAltName( + std::vector<std::string>* dns_names, + std::vector<std::string>* ip_addrs) const { + if (dns_names) + dns_names->clear(); + if (ip_addrs) + ip_addrs->clear(); + + ParseSubjectAltName(cert_handle_, dns_names, ip_addrs); +} + +// static +bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, + std::string* encoded) { + base::StringPiece der; + if (!cert_handle) + return false; + ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert_handle)); + if (!der_data) + return false; + encoded->assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), + CFDataGetLength(der_data)); + return true; +} + +// static +bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, + X509Certificate::OSCertHandle b) { + DCHECK(a && b); + return CFEqual(a, b); +} + +// static X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle( base::PickleIterator* pickle_iter) { - return x509_util::ReadOSCertHandleFromPickle(pickle_iter); + const char* data; + int length; + if (!pickle_iter->ReadData(&data, &length)) + return nullptr; + + return X509Certificate::CreateOSCertHandleFromBytes(data, length); } // static @@ -244,22 +354,121 @@ } // static -void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, +void X509Certificate::GetPublicKeyInfo(OSCertHandle os_cert, size_t* size_bits, PublicKeyType* type) { - x509_util_ios::NSSCertificate nss_cert(cert_handle); - x509_util::GetPublicKeyInfo(nss_cert.cert_handle(), size_bits, type); + *type = kPublicKeyTypeUnknown; + *size_bits = 0; + ScopedX509 cert = OSCertHandleToOpenSSL(os_cert); + if (!cert) + return; + crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert.get())); + if (!scoped_key) + return; + + EVP_PKEY* key = scoped_key.get(); + + switch (key->type) { + case EVP_PKEY_RSA: + *type = kPublicKeyTypeRSA; + break; + case EVP_PKEY_DSA: + *type = kPublicKeyTypeDSA; + break; + case EVP_PKEY_EC: + *type = kPublicKeyTypeECDSA; + break; + case EVP_PKEY_DH: + *type = kPublicKeyTypeDH; + break; + } + *size_bits = EVP_PKEY_bits(key); +} + +bool X509Certificate::SupportsSSLClientAuth() const { + return false; +} + +CFMutableArrayRef X509Certificate::CreateOSCertChainForCert() const { + CFMutableArrayRef cert_list = + CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + if (!cert_list) + return nullptr; + + CFArrayAppendValue(cert_list, os_cert_handle()); + for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) + CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); + + return cert_list; +} + +bool X509Certificate::IsIssuedByEncoded( + const std::vector<std::string>& valid_issuers) { + if (valid_issuers.empty()) + return false; + + // Convert to a temporary list of X509_NAME objects. + // It will own the objects it points to. + crypto::ScopedOpenSSL<STACK_OF(X509_NAME), sk_X509_NAME_free_all> + issuer_names(sk_X509_NAME_new_null()); + if (!issuer_names) + return false; + + for (std::vector<std::string>::const_iterator it = valid_issuers.begin(); + it != valid_issuers.end(); ++it) { + const unsigned char* p = reinterpret_cast<const unsigned char*>(it->data()); + long len = static_cast<long>(it->length()); + X509_NAME* ca_name = d2i_X509_NAME(nullptr, &p, len); + if (ca_name == nullptr) + return false; + sk_X509_NAME_push(issuer_names.get(), ca_name); + } + + ScopedX509 x509_cert = OSCertHandleToOpenSSL(cert_handle_); + if (!x509_cert) + return false; + X509_NAME* cert_issuer = X509_get_issuer_name(x509_cert.get()); + if (cert_issuer == nullptr) + return false; + + for (size_t m = 0; m < sk_X509_NAME_num(issuer_names.get()); ++m) { + X509_NAME* issuer = sk_X509_NAME_value(issuer_names.get(), m); + if (X509_NAME_cmp(issuer, cert_issuer) == 0) { + return true; + } + } + + for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); + it != intermediate_ca_certs_.end(); ++it) { + ScopedX509 intermediate_cert = OSCertHandleToOpenSSL(*it); + if (!intermediate_cert) + return false; + cert_issuer = X509_get_issuer_name(intermediate_cert.get()); + if (cert_issuer == nullptr) + return false; + + for (size_t m = 0; m < sk_X509_NAME_num(issuer_names.get()); ++m) { + X509_NAME* issuer = sk_X509_NAME_value(issuer_names.get(), m); + if (X509_NAME_cmp(issuer, cert_issuer) == 0) { + return true; + } + } + } + + return false; } // static -bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { - x509_util_ios::NSSCertificate nss_cert(cert_handle); - crypto::ScopedSECKEYPublicKey public_key( - CERT_ExtractPublicKey(nss_cert.cert_handle())); - if (!public_key.get()) +bool X509Certificate::IsSelfSigned(OSCertHandle os_cert) { + ScopedX509 cert = OSCertHandleToOpenSSL(os_cert); + if (!cert) return false; - return SECSuccess == CERT_VerifySignedDataWithPublicKey( - &nss_cert.cert_handle()->signatureWrap, public_key.get(), NULL); + crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert.get())); + if (!scoped_key) + return false; + + // NOTE: X509_verify() returns 1 in case of success, 0 or -1 on error. + return X509_verify(cert.get(), scoped_key.get()) == 1; } } // namespace net
diff --git a/net/cert/x509_certificate_openssl_ios.cc b/net/cert/x509_certificate_openssl_ios.cc deleted file mode 100644 index 96ed1de..0000000 --- a/net/cert/x509_certificate_openssl_ios.cc +++ /dev/null
@@ -1,474 +0,0 @@ -// Copyright (c) 2016 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 "net/cert/x509_certificate.h" - -#include <CommonCrypto/CommonDigest.h> -#include <Security/Security.h> - -#include <openssl/x509.h> -#include <openssl/x509v3.h> - -#include "base/mac/scoped_cftyperef.h" -#include "base/pickle.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "crypto/openssl_util.h" -#include "crypto/scoped_openssl_types.h" -#include "net/base/ip_address_number.h" -#include "net/cert/x509_util_openssl.h" -#include "net/ssl/openssl_ssl_util.h" - -using base::ScopedCFTypeRef; - -namespace net { - -namespace { - -using ScopedGENERAL_NAMES = - crypto::ScopedOpenSSL<GENERAL_NAMES, GENERAL_NAMES_free>; - -// Returns true if a given |cert_handle| is actually a valid X.509 certificate -// handle. -// -// SecCertificateCreateFromData() does not always force the immediate parsing of -// the certificate, and as such, may return a SecCertificateRef for an -// invalid/unparsable certificate. Force parsing to occur to ensure that the -// SecCertificateRef is correct. On later versions where -// SecCertificateCreateFromData() immediately parses, rather than lazily, this -// call is cheap, as the subject is cached. -bool IsValidOSCertHandle(SecCertificateRef cert_handle) { - ScopedCFTypeRef<CFStringRef> sanity_check( - SecCertificateCopySubjectSummary(cert_handle)); - return sanity_check != nullptr; -} - -void CreateOSCertHandlesFromPKCS7Bytes( - const char* data, - size_t length, - X509Certificate::OSCertHandles* handles) { - crypto::EnsureOpenSSLInit(); - crypto::OpenSSLErrStackTracer err_cleaner(FROM_HERE); - - CBS der_data; - CBS_init(&der_data, reinterpret_cast<const uint8_t*>(data), length); - STACK_OF(X509)* certs = sk_X509_new_null(); - - if (PKCS7_get_certificates(certs, &der_data)) { - for (size_t i = 0; i < sk_X509_num(certs); ++i) { - X509* x509_cert = sk_X509_value(certs, i); - base::StringPiece der; - if (!x509_util::GetDER(x509_cert, &der)) - return; - handles->push_back(X509Certificate::CreateOSCertHandleFromBytes( - der.data(), der.length())); - } - } - sk_X509_pop_free(certs, X509_free); -} - -void ParsePrincipalValues(X509_NAME* name, - int nid, - std::vector<std::string>* fields) { - for (int index = -1; - (index = X509_NAME_get_index_by_NID(name, nid, index)) != -1;) { - std::string field; - if (!x509_util::ParsePrincipalValueByIndex(name, index, &field)) - break; - fields->push_back(field); - } -} - -void ParsePrincipal(X509Certificate::OSCertHandle os_cert, - X509_NAME* x509_name, - CertPrincipal* principal) { - if (!x509_name) - return; - - ParsePrincipalValues(x509_name, NID_streetAddress, - &principal->street_addresses); - ParsePrincipalValues(x509_name, NID_organizationName, - &principal->organization_names); - ParsePrincipalValues(x509_name, NID_organizationalUnitName, - &principal->organization_unit_names); - ParsePrincipalValues(x509_name, NID_domainComponent, - &principal->domain_components); - - x509_util::ParsePrincipalValueByNID(x509_name, NID_commonName, - &principal->common_name); - x509_util::ParsePrincipalValueByNID(x509_name, NID_localityName, - &principal->locality_name); - x509_util::ParsePrincipalValueByNID(x509_name, NID_stateOrProvinceName, - &principal->state_or_province_name); - x509_util::ParsePrincipalValueByNID(x509_name, NID_countryName, - &principal->country_name); -} - -void ParseSubjectAltName(X509Certificate::OSCertHandle os_cert, - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addresses) { - DCHECK(dns_names || ip_addresses); - ScopedX509 cert = OSCertHandleToOpenSSL(os_cert); - if (!cert.get()) - return; - int index = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1); - X509_EXTENSION* alt_name_ext = X509_get_ext(cert.get(), index); - if (!alt_name_ext) - return; - - ScopedGENERAL_NAMES alt_names( - reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(alt_name_ext))); - if (!alt_names.get()) - return; - - for (size_t i = 0; i < sk_GENERAL_NAME_num(alt_names.get()); ++i) { - const GENERAL_NAME* name = sk_GENERAL_NAME_value(alt_names.get(), i); - if (name->type == GEN_DNS && dns_names) { - const unsigned char* dns_name = ASN1_STRING_data(name->d.dNSName); - if (!dns_name) - continue; - int dns_name_len = ASN1_STRING_length(name->d.dNSName); - dns_names->push_back( - std::string(reinterpret_cast<const char*>(dns_name), dns_name_len)); - } else if (name->type == GEN_IPADD && ip_addresses) { - const unsigned char* ip_addr = name->d.iPAddress->data; - if (!ip_addr) - continue; - int ip_addr_len = name->d.iPAddress->length; - if (ip_addr_len != static_cast<int>(kIPv4AddressSize) && - ip_addr_len != static_cast<int>(kIPv6AddressSize)) { - // http://www.ietf.org/rfc/rfc3280.txt requires subjectAltName iPAddress - // to have 4 or 16 bytes, whereas in a name constraint it includes a - // net mask hence 8 or 32 bytes. Logging to help diagnose any mixup. - LOG(WARNING) << "Bad sized IP Address in cert: " << ip_addr_len; - continue; - } - ip_addresses->push_back( - std::string(reinterpret_cast<const char*>(ip_addr), ip_addr_len)); - } - } -} - -// Used to free a list of X509_NAMEs and the objects it points to. -void sk_X509_NAME_free_all(STACK_OF(X509_NAME) * sk) { - sk_X509_NAME_pop_free(sk, X509_NAME_free); -} - -} // namespace - -// static -X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( - OSCertHandle handle) { - if (!handle) - return nullptr; - return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); -} - -// static -void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { - if (cert_handle) - CFRelease(cert_handle); -} - -void X509Certificate::Initialize() { - crypto::EnsureOpenSSLInit(); - fingerprint_ = CalculateFingerprint(cert_handle_); - ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); - ScopedX509 x509_cert = OSCertHandleToOpenSSL(cert_handle_); - if (!x509_cert) - return; - ASN1_INTEGER* serial_num = X509_get_serialNumber(x509_cert.get()); - if (serial_num) { - // ASN1_INTEGERS represent the decoded number, in a format internal to - // OpenSSL. Most notably, this may have leading zeroes stripped off for - // numbers whose first byte is >= 0x80. Thus, it is necessary to - // re-encoded the integer back into DER, which is what the interface - // of X509Certificate exposes, to ensure callers get the proper (DER) - // value. - int bytes_required = i2c_ASN1_INTEGER(serial_num, nullptr); - unsigned char* buffer = reinterpret_cast<unsigned char*>( - base::WriteInto(&serial_number_, bytes_required + 1)); - int bytes_written = i2c_ASN1_INTEGER(serial_num, &buffer); - DCHECK_EQ(static_cast<size_t>(bytes_written), serial_number_.size()); - } - - ParsePrincipal(cert_handle_, X509_get_subject_name(x509_cert.get()), - &subject_); - ParsePrincipal(cert_handle_, X509_get_issuer_name(x509_cert.get()), &issuer_); - x509_util::ParseDate(X509_get_notBefore(x509_cert.get()), &valid_start_); - x509_util::ParseDate(X509_get_notAfter(x509_cert.get()), &valid_expiry_); -} - -// static -SHA1HashValue X509Certificate::CalculateFingerprint(OSCertHandle cert) { - SHA1HashValue sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - - ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert)); - if (!cert_data) - return sha1; - DCHECK(CFDataGetBytePtr(cert_data)); - DCHECK_NE(0, CFDataGetLength(cert_data)); - CC_SHA1(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), sha1.data); - - return sha1; -} - -// static -SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) { - SHA256HashValue sha256; - memset(sha256.data, 0, sizeof(sha256.data)); - - ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert)); - if (!cert_data) - return sha256; - DCHECK(CFDataGetBytePtr(cert_data)); - DCHECK_NE(0, CFDataGetLength(cert_data)); - CC_SHA256(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), - sha256.data); - - return sha256; -} - -// static -SHA1HashValue X509Certificate::CalculateCAFingerprint( - const OSCertHandles& intermediates) { - SHA1HashValue sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - - CC_SHA1_CTX sha1_ctx; - CC_SHA1_Init(&sha1_ctx); - for (size_t i = 0; i < intermediates.size(); ++i) { - ScopedCFTypeRef<CFDataRef> cert_data( - SecCertificateCopyData(intermediates[i])); - if (!cert_data) - return sha1; - CC_SHA1_Update(&sha1_ctx, CFDataGetBytePtr(cert_data), - CFDataGetLength(cert_data)); - } - CC_SHA1_Final(sha1.data, &sha1_ctx); - return sha1; -} - -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, - size_t length) { - ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy( - kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), - base::checked_cast<CFIndex>(length), kCFAllocatorNull)); - if (!cert_data) - return nullptr; - OSCertHandle cert_handle = SecCertificateCreateWithData(nullptr, cert_data); - if (!cert_handle) - return nullptr; - if (!IsValidOSCertHandle(cert_handle)) { - CFRelease(cert_handle); - return nullptr; - } - return cert_handle; -} - -// static -X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( - const char* data, - size_t length, - Format format) { - OSCertHandles results; - - switch (format) { - case FORMAT_SINGLE_CERTIFICATE: { - OSCertHandle handle = - X509Certificate::CreateOSCertHandleFromBytes(data, length); - if (handle) - results.push_back(handle); - break; - } - case FORMAT_PKCS7: { - CreateOSCertHandlesFromPKCS7Bytes(data, length, &results); - break; - } - default: { - NOTREACHED() << "Certificate format " << format << " unimplemented"; - break; - } - } - - return results; -} - -void X509Certificate::GetSubjectAltName( - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addrs) const { - if (dns_names) - dns_names->clear(); - if (ip_addrs) - ip_addrs->clear(); - - ParseSubjectAltName(cert_handle_, dns_names, ip_addrs); -} - -// static -bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, - std::string* encoded) { - base::StringPiece der; - if (!cert_handle) - return false; - ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert_handle)); - if (!der_data) - return false; - encoded->assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), - CFDataGetLength(der_data)); - return true; -} - -// static -bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, - X509Certificate::OSCertHandle b) { - DCHECK(a && b); - return CFEqual(a, b); -} - -// static -X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle( - base::PickleIterator* pickle_iter) { - const char* data; - int length; - if (!pickle_iter->ReadData(&data, &length)) - return nullptr; - - return X509Certificate::CreateOSCertHandleFromBytes(data, length); -} - -// static -bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, - base::Pickle* pickle) { - ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert_handle)); - if (!cert_data) - return false; - - return pickle->WriteData( - reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)), - CFDataGetLength(cert_data)); -} - -// static -void X509Certificate::GetPublicKeyInfo(OSCertHandle os_cert, - size_t* size_bits, - PublicKeyType* type) { - *type = kPublicKeyTypeUnknown; - *size_bits = 0; - ScopedX509 cert = OSCertHandleToOpenSSL(os_cert); - if (!cert) - return; - crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert.get())); - if (!scoped_key) - return; - - EVP_PKEY* key = scoped_key.get(); - - switch (key->type) { - case EVP_PKEY_RSA: - *type = kPublicKeyTypeRSA; - break; - case EVP_PKEY_DSA: - *type = kPublicKeyTypeDSA; - break; - case EVP_PKEY_EC: - *type = kPublicKeyTypeECDSA; - break; - case EVP_PKEY_DH: - *type = kPublicKeyTypeDH; - break; - } - *size_bits = EVP_PKEY_bits(key); -} - -bool X509Certificate::SupportsSSLClientAuth() const { - return false; -} - -CFMutableArrayRef X509Certificate::CreateOSCertChainForCert() const { - CFMutableArrayRef cert_list = - CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if (!cert_list) - return nullptr; - - CFArrayAppendValue(cert_list, os_cert_handle()); - for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) - CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); - - return cert_list; -} - -bool X509Certificate::IsIssuedByEncoded( - const std::vector<std::string>& valid_issuers) { - if (valid_issuers.empty()) - return false; - - // Convert to a temporary list of X509_NAME objects. - // It will own the objects it points to. - crypto::ScopedOpenSSL<STACK_OF(X509_NAME), sk_X509_NAME_free_all> - issuer_names(sk_X509_NAME_new_null()); - if (!issuer_names) - return false; - - for (std::vector<std::string>::const_iterator it = valid_issuers.begin(); - it != valid_issuers.end(); ++it) { - const unsigned char* p = reinterpret_cast<const unsigned char*>(it->data()); - long len = static_cast<long>(it->length()); - X509_NAME* ca_name = d2i_X509_NAME(nullptr, &p, len); - if (ca_name == nullptr) - return false; - sk_X509_NAME_push(issuer_names.get(), ca_name); - } - - ScopedX509 x509_cert = OSCertHandleToOpenSSL(cert_handle_); - if (!x509_cert) - return false; - X509_NAME* cert_issuer = X509_get_issuer_name(x509_cert.get()); - if (cert_issuer == nullptr) - return false; - - for (size_t m = 0; m < sk_X509_NAME_num(issuer_names.get()); ++m) { - X509_NAME* issuer = sk_X509_NAME_value(issuer_names.get(), m); - if (X509_NAME_cmp(issuer, cert_issuer) == 0) { - return true; - } - } - - for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); - it != intermediate_ca_certs_.end(); ++it) { - ScopedX509 intermediate_cert = OSCertHandleToOpenSSL(*it); - if (!intermediate_cert) - return false; - cert_issuer = X509_get_issuer_name(intermediate_cert.get()); - if (cert_issuer == nullptr) - return false; - - for (size_t m = 0; m < sk_X509_NAME_num(issuer_names.get()); ++m) { - X509_NAME* issuer = sk_X509_NAME_value(issuer_names.get(), m); - if (X509_NAME_cmp(issuer, cert_issuer) == 0) { - return true; - } - } - } - - return false; -} - -// static -bool X509Certificate::IsSelfSigned(OSCertHandle os_cert) { - ScopedX509 cert = OSCertHandleToOpenSSL(os_cert); - if (!cert) - return false; - crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert.get())); - if (!scoped_key) - return false; - - // NOTE: X509_verify() returns 1 in case of success, 0 or -1 on error. - return X509_verify(cert.get(), scoped_key.get()) == 1; -} - -} // namespace net
diff --git a/net/cert/x509_certificate_win.cc b/net/cert/x509_certificate_win.cc index 6d1fbe8..7d8e531 100644 --- a/net/cert/x509_certificate_win.cc +++ b/net/cert/x509_certificate_win.cc
@@ -6,6 +6,8 @@ #include <memory> +#include <openssl/sha.h> + #include "base/logging.h" #include "base/memory/free_deleter.h" #include "base/numerics/safe_conversions.h" @@ -18,13 +20,6 @@ #include "crypto/sha2.h" #include "net/base/net_errors.h" -// Implement CalculateChainFingerprint() with our native crypto library. -#if defined(USE_OPENSSL) -#include <openssl/sha.h> -#else -#include <blapi.h> -#endif - using base::Time; namespace net { @@ -340,7 +335,6 @@ SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); -#if defined(USE_OPENSSL) SHA_CTX ctx; if (!SHA1_Init(&ctx)) return sha1; @@ -350,19 +344,6 @@ return sha1; } SHA1_Final(sha1.data, &ctx); -#else // !USE_OPENSSL - SHA1Context* sha1_ctx = SHA1_NewContext(); - if (!sha1_ctx) - return sha1; - SHA1_Begin(sha1_ctx); - for (size_t i = 0; i < intermediates.size(); ++i) { - PCCERT_CONTEXT ca_cert = intermediates[i]; - SHA1_Update(sha1_ctx, ca_cert->pbCertEncoded, ca_cert->cbCertEncoded); - } - unsigned int result_len; - SHA1_End(sha1_ctx, sha1.data, &result_len, SHA1_LENGTH); - SHA1_DestroyContext(sha1_ctx, PR_TRUE); -#endif // USE_OPENSSL return sha1; }
diff --git a/net/cert/x509_util_ios.cc b/net/cert/x509_util_ios.cc deleted file mode 100644 index 0c644a8..0000000 --- a/net/cert/x509_util_ios.cc +++ /dev/null
@@ -1,142 +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. - -#include "net/cert/x509_util_ios.h" - -#include <cert.h> -#include <CommonCrypto/CommonDigest.h> -#include <nss.h> -#include <prtypes.h> - -#include "base/mac/scoped_cftyperef.h" -#include "base/memory/ref_counted.h" -#include "crypto/nss_util.h" -#include "net/cert/x509_certificate.h" -#include "net/cert/x509_util_nss.h" - -using base::ScopedCFTypeRef; - -namespace net { -namespace x509_util_ios { - -namespace { - -// Creates an NSS certificate handle from |data|, which is |length| bytes in -// size. -CERTCertificate* CreateNSSCertHandleFromBytes(const char* data, - int length) { - if (length < 0) - return NULL; - - crypto::EnsureNSSInit(); - - if (!NSS_IsInitialized()) - return NULL; - - SECItem der_cert; - der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data)); - der_cert.len = length; - der_cert.type = siDERCertBuffer; - - // Parse into a certificate structure. - return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL, - PR_FALSE, PR_TRUE); -} - -} // namespace - -CERTCertificate* CreateNSSCertHandleFromOSHandle( - SecCertificateRef cert_handle) { - ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert_handle)); - return CreateNSSCertHandleFromBytes( - reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)), - CFDataGetLength(cert_data)); -} - -SecCertificateRef CreateOSCertHandleFromNSSHandle( - CERTCertificate* nss_cert_handle) { - return X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<const char*>(nss_cert_handle->derCert.data), - nss_cert_handle->derCert.len); -} - -scoped_refptr<X509Certificate> CreateCertFromNSSHandles( - CERTCertificate* cert_handle, - const std::vector<CERTCertificate*>& intermediates) { - ScopedCFTypeRef<SecCertificateRef> os_server_cert( - CreateOSCertHandleFromNSSHandle(cert_handle)); - if (!os_server_cert) - return nullptr; - std::vector<SecCertificateRef> os_intermediates; - for (size_t i = 0; i < intermediates.size(); ++i) { - SecCertificateRef intermediate = - CreateOSCertHandleFromNSSHandle(intermediates[i]); - if (!intermediate) - break; - os_intermediates.push_back(intermediate); - } - - scoped_refptr<X509Certificate> cert = nullptr; - if (intermediates.size() == os_intermediates.size()) { - cert = X509Certificate::CreateFromHandle(os_server_cert, - os_intermediates); - } - - for (size_t i = 0; i < os_intermediates.size(); ++i) - CFRelease(os_intermediates[i]); - return cert; -} - -SHA1HashValue CalculateFingerprintNSS(CERTCertificate* cert) { - DCHECK(cert->derCert.data); - DCHECK_NE(0U, cert->derCert.len); - SHA1HashValue sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - CC_SHA1(cert->derCert.data, cert->derCert.len, sha1.data); - return sha1; -} - -// NSSCertificate implementation. - -NSSCertificate::NSSCertificate(SecCertificateRef cert_handle) { - nss_cert_handle_ = CreateNSSCertHandleFromOSHandle(cert_handle); - DLOG_IF(ERROR, cert_handle && !nss_cert_handle_) - << "Could not convert SecCertificateRef to CERTCertificate*"; -} - -NSSCertificate::~NSSCertificate() { - CERT_DestroyCertificate(nss_cert_handle_); -} - -CERTCertificate* NSSCertificate::cert_handle() const { - return nss_cert_handle_; -} - -// NSSCertChain implementation - -NSSCertChain::NSSCertChain(X509Certificate* certificate) { - DCHECK(certificate); - certs_.push_back(CreateNSSCertHandleFromOSHandle( - certificate->os_cert_handle())); - const X509Certificate::OSCertHandles& cert_intermediates = - certificate->GetIntermediateCertificates(); - for (size_t i = 0; i < cert_intermediates.size(); ++i) - certs_.push_back(CreateNSSCertHandleFromOSHandle(cert_intermediates[i])); -} - -NSSCertChain::~NSSCertChain() { - for (size_t i = 0; i < certs_.size(); ++i) - CERT_DestroyCertificate(certs_[i]); -} - -CERTCertificate* NSSCertChain::cert_handle() const { - return certs_.empty() ? NULL : certs_.front(); -} - -const std::vector<CERTCertificate*>& NSSCertChain::cert_chain() const { - return certs_; -} - -} // namespace x509_util_ios -} // namespace net
diff --git a/net/cert/x509_util_ios.h b/net/cert/x509_util_ios.h deleted file mode 100644 index eb937552..0000000 --- a/net/cert/x509_util_ios.h +++ /dev/null
@@ -1,73 +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. - -// This file contains functions for iOS to glue NSS and Security.framework -// together. - -#ifndef NET_CERT_X509_UTIL_IOS_H_ -#define NET_CERT_X509_UTIL_IOS_H_ - -#include <Security/Security.h> -#include <vector> - -#include "base/memory/ref_counted.h" -#include "net/cert/x509_cert_types.h" - -// Forward declaration; real one in <cert.h> -typedef struct CERTCertificateStr CERTCertificate; - -namespace net { - -class X509Certificate; - -namespace x509_util_ios { - -// Converts a Security.framework certificate handle (SecCertificateRef) into -// an NSS certificate handle (CERTCertificate*). -CERTCertificate* CreateNSSCertHandleFromOSHandle(SecCertificateRef cert_handle); - -// Converts an NSS certificate handle (CERTCertificate*) into a -// Security.framework handle (SecCertificateRef) -SecCertificateRef CreateOSCertHandleFromNSSHandle( - CERTCertificate* nss_cert_handle); - -// Create a new X509Certificate from the specified NSS server cert and -// intermediates. This is functionally equivalent to -// X509Certificate::CreateFromHandle(), except it supports receiving -// NSS CERTCertificate*s rather than iOS SecCertificateRefs. -scoped_refptr<X509Certificate> CreateCertFromNSSHandles( - CERTCertificate* cert_handle, - const std::vector<CERTCertificate*>& intermediates); - -SHA1HashValue CalculateFingerprintNSS(CERTCertificate* cert); - -// This is a wrapper class around the native NSS certificate handle. -// The constructor copies the certificate data from |cert_handle| and -// uses the NSS library to parse it. -class NSSCertificate { - public: - explicit NSSCertificate(SecCertificateRef cert_handle); - ~NSSCertificate(); - CERTCertificate* cert_handle() const; - private: - CERTCertificate* nss_cert_handle_; -}; - -// A wrapper class that loads a certificate and all of its intermediates into -// NSS. This is necessary for libpkix path building to be able to locate -// needed intermediates. -class NSSCertChain { - public: - explicit NSSCertChain(X509Certificate* certificate); - ~NSSCertChain(); - CERTCertificate* cert_handle() const; - const std::vector<CERTCertificate*>& cert_chain() const; - private: - std::vector<CERTCertificate*> certs_; -}; - -} // namespace x509_util_ios -} // namespace net - -#endif // NET_CERT_X509_UTIL_IOS_H_
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc index d059eb3..134c085 100644 --- a/net/cert/x509_util_nss.cc +++ b/net/cert/x509_util_nss.cc
@@ -1,9 +1,7 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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 "net/cert/x509_util_nss.h" - #include <cert.h> // Must be included before certdb.h #include <certdb.h> #include <cryptohi.h> @@ -19,6 +17,7 @@ #include "base/debug/leak_annotations.h" #include "base/logging.h" #include "base/memory/singleton.h" +#include "base/numerics/safe_conversions.h" #include "base/pickle.h" #include "base/strings/stringprintf.h" #include "crypto/ec_private_key.h" @@ -29,164 +28,389 @@ #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 { -// Creates a Certificate object that may be passed to the SignCertificate -// method to generate an X509 certificate. -// Returns NULL if an error is encountered in the certificate creation -// process. -// Caller responsible for freeing returned certificate object. -CERTCertificate* CreateCertificate(SECKEYPublicKey* public_key, - const std::string& subject, - uint32_t serial_number, - base::Time not_valid_before, - base::Time not_valid_after) { - // Create info about public key. - CERTSubjectPublicKeyInfo* spki = - SECKEY_CreateSubjectPublicKeyInfo(public_key); - if (!spki) - return NULL; +// Microsoft User Principal Name: 1.3.6.1.4.1.311.20.2.3 +const uint8_t kUpnOid[] = {0x2b, 0x6, 0x1, 0x4, 0x1, + 0x82, 0x37, 0x14, 0x2, 0x3}; - // Create the certificate request. - CERTName* subject_name = - CERT_AsciiToName(const_cast<char*>(subject.c_str())); - CERTCertificateRequest* cert_request = - CERT_CreateCertificateRequest(subject_name, spki, NULL); - SECKEY_DestroySubjectPublicKeyInfo(spki); +// 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); - if (!cert_request) { - PRErrorCode prerr = PR_GetError(); - LOG(ERROR) << "Failed to create certificate request: " << prerr; - CERT_DestroyName(subject_name); - return NULL; + 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); } - CERTValidity* validity = CERT_CreateValidity( - crypto::BaseTimeToPRTime(not_valid_before), - crypto::BaseTimeToPRTime(not_valid_after)); - if (!validity) { - PRErrorCode prerr = PR_GetError(); - LOG(ERROR) << "Failed to create certificate validity object: " << prerr; - CERT_DestroyName(subject_name); - CERT_DestroyCertificateRequest(cert_request); - return NULL; - } - CERTCertificate* cert = CERT_CreateCertificate(serial_number, subject_name, - validity, cert_request); - if (!cert) { - PRErrorCode prerr = PR_GetError(); - LOG(ERROR) << "Failed to create certificate: " << prerr; - } - - // Cleanup for resources used to generate the cert. - CERT_DestroyName(subject_name); - CERT_DestroyValidity(validity); - CERT_DestroyCertificateRequest(cert_request); - - return cert; + return SECSuccess; } -SECOidTag ToSECOid(x509_util::DigestAlgorithm alg) { - switch (alg) { - case x509_util::DIGEST_SHA1: - return SEC_OID_SHA1; - case x509_util::DIGEST_SHA256: - return SEC_OID_SHA256; - } - return SEC_OID_UNKNOWN; -} +typedef std::unique_ptr<CERTName, + crypto::NSSDestroyer<CERTName, CERT_DestroyName>> + ScopedCERTName; -// Signs a certificate object, with |key| generating a new X509Certificate -// and destroying the passed certificate object (even when NULL is returned). -// The logic of this method references SignCert() in NSS utility certutil: -// http://mxr.mozilla.org/security/ident?i=SignCert. -// Returns true on success or false if an error is encountered in the -// certificate signing process. -bool SignCertificate( - CERTCertificate* cert, - SECKEYPrivateKey* key, - SECOidTag hash_algorithm) { - // |arena| is used to encode the cert. - PLArenaPool* arena = cert->arena; - SECOidTag algo_id = SEC_GetSignatureAlgorithmOidTag(key->keyType, - hash_algorithm); - if (algo_id == SEC_OID_UNKNOWN) - return false; +// 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; - SECStatus rv = SECOID_SetAlgorithmID(arena, &cert->signature, algo_id, 0); + 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 false; + return NULL; - // Generate a cert of version 3. - *(cert->version.data) = 2; - cert->version.len = 1; - - SECItem der = { siBuffer, NULL, 0 }; - - // Use ASN1 DER to encode the cert. - void* encode_result = SEC_ASN1EncodeItem( - NULL, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); - if (!encode_result) - return false; - - // Allocate space to contain the signed cert. - SECItem result = { siBuffer, NULL, 0 }; - - // Sign the ASN1 encoded cert and save it to |result|. - rv = DerSignData(arena, &result, &der, key, algo_id); - PORT_Free(der.data); - if (rv != SECSuccess) { - DLOG(ERROR) << "DerSignData: " << PORT_GetError(); - return false; - } - - // Save the signed result to the cert. - cert->derCert = result; - - return true; + return name.release(); } } // namespace namespace x509_util { -bool CreateSelfSignedCert(crypto::RSAPrivateKey* key, - DigestAlgorithm alg, - const std::string& subject, - uint32_t serial_number, - base::Time not_valid_before, - base::Time not_valid_after, - std::string* der_cert) { - DCHECK(key); - DCHECK(!strncmp(subject.c_str(), "CN=", 3U)); - CERTCertificate* cert = CreateCertificate(key->public_key(), - subject, - serial_number, - not_valid_before, - not_valid_after); - if (!cert) - return false; +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 - if (!SignCertificate(cert, key->key(), ToSECOid(alg))) { - CERT_DestroyCertificate(cert); - return false; + // 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; + } + } + } } - der_cert->assign(reinterpret_cast<char*>(cert->derCert.data), - cert->derCert.len); - CERT_DestroyCertificate(cert); - return true; + // 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); + } + } } -bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate, - std::string* token) { - NOTIMPLEMENTED(); +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); +} + +void GetRFC822SubjectAltNames(CERTCertificate* cert_handle, + std::vector<std::string>* names) { + crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0)); + DCHECK(alt_name.get()); + + names->clear(); + SECStatus rv = CERT_FindCertExtension( + cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get()); + if (rv != SECSuccess) + return; + + crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + DCHECK(arena.get()); + + CERTGeneralName* alt_name_list; + alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get()); + + CERTGeneralName* name = alt_name_list; + while (name) { + if (name->type == certRFC822Name) { + names->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; + } +} + +void GetUPNSubjectAltNames(CERTCertificate* cert_handle, + std::vector<std::string>* names) { + crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0)); + DCHECK(alt_name.get()); + + names->clear(); + SECStatus rv = CERT_FindCertExtension( + cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get()); + if (rv != SECSuccess) + return; + + crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + DCHECK(arena.get()); + + CERTGeneralName* alt_name_list; + alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get()); + + CERTGeneralName* name = alt_name_list; + while (name) { + if (name->type == certOtherName) { + OtherName* on = &name->name.OthName; + if (on->oid.len == sizeof(kUpnOid) && + memcmp(on->oid.data, kUpnOid, sizeof(kUpnOid)) == 0) { + SECItem decoded; + if (SEC_QuickDERDecodeItem(arena.get(), &decoded, + SEC_ASN1_GET(SEC_UTF8StringTemplate), + &name->name.OthName.name) == SECSuccess) { + names->push_back( + std::string(reinterpret_cast<char*>(decoded.data), decoded.len)); + } + } + } + name = CERT_GetNextGeneralName(name); + if (name == alt_name_list) + break; + } +} + +X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( + const char* data, + size_t length, + X509Certificate::Format format) { + X509Certificate::OSCertHandles 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.data(), base::checked_cast<int>(data_copy.size()), + CollectCertsCallback, &results); + if (result != SECSuccess) + results.clear(); + break; + } + default: + NOTREACHED() << "Certificate format " << format << " unimplemented"; + break; + } + + return results; +} + +X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( + base::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; } -} // namespace x509_util +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; +} -} // namespace net +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/cert/x509_util_nss.h b/net/cert/x509_util_nss.h index c656264..b0ba592 100644 --- a/net/cert/x509_util_nss.h +++ b/net/cert/x509_util_nss.h
@@ -28,7 +28,7 @@ namespace x509_util { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) // Parses the Principal attribute from |name| and outputs the result in // |principal|. void ParsePrincipal(CERTName* name, @@ -127,7 +127,7 @@ std::string GetUniqueNicknameForSlot(const std::string& nickname, const SECItem* subject, PK11SlotInfo* slot); -#endif // defined(USE_NSS_VERIFIER) +#endif // defined(USE_NSS_CERTS) } // namespace x509_util
diff --git a/net/cert/x509_util_nss_certs.cc b/net/cert/x509_util_nss_certs.cc deleted file mode 100644 index a94a5d47..0000000 --- a/net/cert/x509_util_nss_certs.cc +++ /dev/null
@@ -1,420 +0,0 @@ -// 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 <memory> - -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/numerics/safe_conversions.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 { - -// Microsoft User Principal Name: 1.3.6.1.4.1.311.20.2.3 -const uint8_t kUpnOid[] = {0x2b, 0x6, 0x1, 0x4, 0x1, - 0x82, 0x37, 0x14, 0x2, 0x3}; - -// 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 std::unique_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); -} - -void GetRFC822SubjectAltNames(CERTCertificate* cert_handle, - std::vector<std::string>* names) { - crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0)); - DCHECK(alt_name.get()); - - names->clear(); - SECStatus rv = CERT_FindCertExtension( - cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get()); - if (rv != SECSuccess) - return; - - crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - DCHECK(arena.get()); - - CERTGeneralName* alt_name_list; - alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get()); - - CERTGeneralName* name = alt_name_list; - while (name) { - if (name->type == certRFC822Name) { - names->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; - } -} - -void GetUPNSubjectAltNames(CERTCertificate* cert_handle, - std::vector<std::string>* names) { - crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0)); - DCHECK(alt_name.get()); - - names->clear(); - SECStatus rv = CERT_FindCertExtension( - cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get()); - if (rv != SECSuccess) - return; - - crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - DCHECK(arena.get()); - - CERTGeneralName* alt_name_list; - alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get()); - - CERTGeneralName* name = alt_name_list; - while (name) { - if (name->type == certOtherName) { - OtherName* on = &name->name.OthName; - if (on->oid.len == sizeof(kUpnOid) && - memcmp(on->oid.data, kUpnOid, sizeof(kUpnOid)) == 0) { - SECItem decoded; - if (SEC_QuickDERDecodeItem(arena.get(), &decoded, - SEC_ASN1_GET(SEC_UTF8StringTemplate), - &name->name.OthName.name) == SECSuccess) { - names->push_back( - std::string(reinterpret_cast<char*>(decoded.data), decoded.len)); - } - } - } - name = CERT_GetNextGeneralName(name); - if (name == alt_name_list) - break; - } -} - -X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( - const char* data, - size_t length, - X509Certificate::Format format) { - X509Certificate::OSCertHandles 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.data(), base::checked_cast<int>(data_copy.size()), - CollectCertsCallback, &results); - if (result != SECSuccess) - results.clear(); - break; - } - default: - NOTREACHED() << "Certificate format " << format << " unimplemented"; - break; - } - - return results; -} - -X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( - base::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/cert/x509_util_unittest.cc b/net/cert/x509_util_unittest.cc index 665fe15..2da48d80 100644 --- a/net/cert/x509_util_unittest.cc +++ b/net/cert/x509_util_unittest.cc
@@ -188,7 +188,6 @@ EXPECT_FALSE(cert->HasExpired()); } -#if defined(USE_OPENSSL) // This is a test case based on // http://blogs.msdn.com/b/openspecification/archive/2013/03/26/ntlm-and-channel-binding-hash-aka-exteneded-protection-for-authentication.aspx // There doesn't seem to be too many public test vectors for channel bindings. @@ -698,7 +697,6 @@ x509_util::GetTLSServerEndPointChannelBinding(*cert, &channel_bindings)); EXPECT_TRUE(channel_bindings.empty()); } -#endif } // namespace x509_util
diff --git a/net/http/des.cc b/net/http/des.cc index 4fce9ccd..4f05022 100644 --- a/net/http/des.cc +++ b/net/http/des.cc
@@ -4,16 +4,10 @@ #include "net/http/des.h" -#include "base/logging.h" - -#if defined(USE_OPENSSL) #include <openssl/des.h> + +#include "base/logging.h" #include "crypto/openssl_util.h" -#elif defined(OS_IOS) -#include <CommonCrypto/CommonCryptor.h> -#else -#error "Unknown platform" -#endif // The iOS version of DESEncrypt is our own code. // DESSetKeyParity and DESMakeKey are based on @@ -80,8 +74,6 @@ key[7] = DESSetKeyParity((raw[6] << 1)); } -#if defined(USE_OPENSSL) - void DESEncrypt(const uint8_t* key, const uint8_t* src, uint8_t* hash) { crypto::EnsureOpenSSLInit(); @@ -93,17 +85,4 @@ reinterpret_cast<DES_cblock*>(hash), &ks, DES_ENCRYPT); } -#elif defined(OS_IOS) - -void DESEncrypt(const uint8_t* key, const uint8_t* src, uint8_t* hash) { - CCCryptorStatus status; - size_t data_out_moved = 0; - status = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, - key, 8, NULL, src, 8, hash, 8, &data_out_moved); - DCHECK(status == kCCSuccess); - DCHECK(data_out_moved == 8); -} - -#endif - } // namespace net
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index d160c31..ee64179c 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc
@@ -263,8 +263,8 @@ std::string origin_host = ApplyHostMappingRules(request_info.url, &destination).host(); QuicServerId server_id(destination, request_info.privacy_mode); - if (session_->quic_stream_factory()->CanUseExistingSession( - server_id, request_info.privacy_mode, origin_host)) + if (session_->quic_stream_factory()->CanUseExistingSession(server_id, + origin_host)) return alternative_service; // Cache this entry if we don't have a non-broken Alt-Svc yet.
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc index 3eac0303..2140209 100644 --- a/net/http/transport_security_state_unittest.cc +++ b/net/http/transport_security_state_unittest.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_piece.h" #include "base/test/histogram_tester.h" #include "base/values.h" +#include "crypto/openssl_util.h" #include "crypto/sha2.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" @@ -34,12 +35,6 @@ #include "net/test/cert_test_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_OPENSSL) -#include "crypto/openssl_util.h" -#else -#include "crypto/nss_util.h" -#endif - namespace net { namespace { @@ -236,11 +231,7 @@ class TransportSecurityStateTest : public testing::Test { public: void SetUp() override { -#if defined(USE_OPENSSL) crypto::EnsureOpenSSLInit(); -#else - crypto::EnsureNSSInit(); -#endif } static void DisableStaticPins(TransportSecurityState* state) {
diff --git a/net/net.gyp b/net/net.gyp index e59ce18..7a4ef6b 100644 --- a/net/net.gyp +++ b/net/net.gyp
@@ -170,6 +170,7 @@ '../crypto/crypto.gyp:crypto_test_support', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', + '../third_party/boringssl/boringssl.gyp:boringssl', '../third_party/zlib/zlib.gyp:zlib', '../url/url.gyp:url_url_features', '../url/url.gyp:url_lib', @@ -223,13 +224,7 @@ 'ssl/client_cert_store_nss_unittest.cc', ], }], - [ 'use_openssl == 1', { - # Avoid compiling/linking with the system library. - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - }], - [ 'use_nss_verifier == 1', { + [ 'use_nss_certs == 1', { 'conditions': [ [ 'desktop_linux == 1 or chromeos == 1', { 'dependencies': [ @@ -263,13 +258,13 @@ 'http/http_auth_handler_negotiate_unittest.cc', ], }], - [ 'use_nss_verifier == 0', { + [ 'use_nss_certs == 0', { # Only include this test when using NSS for cert verification. 'sources!': [ 'cert_net/nss_ocsp_unittest.cc', ], }], - [ 'use_nss_verifier == 0 and OS == "ios"', { + [ 'OS == "ios"', { # Only include these files on iOS when using NSS for cert # verification. 'sources!': [ @@ -277,24 +272,6 @@ 'cert/x509_util_ios.h', ], }], - [ 'use_nss_verifier == 1 and OS == "ios"', { - 'sources!': [ - 'cert/cert_verify_proc_ios.cc', - 'cert/cert_verify_proc_ios.h', - 'cert/x509_certificate_openssl_ios.cc', - ], - }], - [ 'use_openssl==1', { - 'sources!': [ - 'quic/test_tools/crypto_test_utils_nss.cc', - ], - }, { # else !use_openssl: remove the unneeded files and pull in NSS. - 'sources!': [ - 'quic/test_tools/crypto_test_utils_openssl.cc', - 'ssl/ssl_client_session_cache_openssl_unittest.cc', - ], - }, - ], [ 'use_openssl_certs == 0', { 'sources!': [ 'ssl/openssl_client_key_store_unittest.cc', @@ -692,7 +669,7 @@ 'test/spawned_test_server/spawned_test_server.h', ], }], - ['use_nss_verifier == 1', { + ['use_nss_certs == 1', { 'conditions': [ [ 'desktop_linux == 1 or chromeos == 1', { 'dependencies': [
diff --git a/net/net.gypi b/net/net.gypi index 003e7d56f..80df25b 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -519,8 +519,6 @@ 'base/network_interfaces_win.cc', 'base/network_quality_estimator.cc', 'base/network_quality_estimator.h', - 'base/nss_memio.c', - 'base/nss_memio.h', 'base/platform_mime_util.h', 'base/platform_mime_util_linux.cc', 'base/platform_mime_util_mac.mm', @@ -588,12 +586,10 @@ 'cert/ct_log_response_parser.h', 'cert/ct_log_verifier.cc', 'cert/ct_log_verifier.h', - 'cert/ct_log_verifier_nss.cc', 'cert/ct_log_verifier_openssl.cc', 'cert/ct_log_verifier_util.cc', 'cert/ct_log_verifier_util.h', 'cert/ct_objects_extractor.h', - 'cert/ct_objects_extractor_nss.cc', 'cert/ct_objects_extractor_openssl.cc', 'cert/ct_serialization.cc', 'cert/ct_serialization.h', @@ -602,7 +598,6 @@ 'cert/ev_root_ca_metadata.cc', 'cert/ev_root_ca_metadata.h', 'cert/jwk_serializer.h', - 'cert/jwk_serializer_nss.cc', 'cert/jwk_serializer_openssl.cc', 'cert/merkle_consistency_proof.cc', 'cert/merkle_consistency_proof.h', @@ -616,7 +611,6 @@ 'cert/nss_cert_database_chromeos.h', 'cert/nss_profile_filter_chromeos.cc', 'cert/nss_profile_filter_chromeos.h', - 'cert/scoped_nss_types.h', 'cert/sct_status_flags.h', 'cert/test_root_certs.cc', 'cert/test_root_certs.h', @@ -630,17 +624,13 @@ 'cert/x509_certificate_ios.cc', 'cert/x509_certificate_mac.cc', 'cert/x509_certificate_nss.cc', - 'cert/x509_certificate_openssl_ios.cc', 'cert/x509_certificate_win.cc', 'cert/x509_util_android.cc', 'cert/x509_util_android.h', - 'cert/x509_util_ios.cc', - 'cert/x509_util_ios.h', 'cert/x509_util_mac.cc', 'cert/x509_util_mac.h', - 'cert/x509_util_nss.cc', 'cert/x509_util_nss.h', - 'cert/x509_util_nss_certs.cc', + 'cert/x509_util_nss.cc', 'cert_net/cert_net_fetcher_impl.cc', 'cert_net/cert_net_fetcher_impl.h', 'cookies/canonical_cookie.cc', @@ -1003,18 +993,9 @@ 'proxy/proxy_service.h', 'quic/bidirectional_stream_quic_impl.cc', 'quic/bidirectional_stream_quic_impl.h', - 'quic/crypto/aead_base_decrypter_nss.cc', - 'quic/crypto/aead_base_encrypter_nss.cc', - 'quic/crypto/aes_128_gcm_12_decrypter_nss.cc', - 'quic/crypto/aes_128_gcm_12_encrypter_nss.cc', 'quic/crypto/cert_compressor.cc', 'quic/crypto/cert_compressor.h', - 'quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc', - 'quic/crypto/chacha20_poly1305_rfc7539_encrypter_nss.cc', - 'quic/crypto/channel_id_nss.cc', - 'quic/crypto/p256_key_exchange_nss.cc', 'quic/crypto/proof_source_chromium.h', - 'quic/crypto/proof_source_chromium_nss.cc', 'quic/crypto/proof_source_chromium_openssl.cc', 'quic/crypto/quic_compressed_certs_cache.cc', 'quic/crypto/quic_compressed_certs_cache.h', @@ -1068,8 +1049,6 @@ 'socket/client_socket_pool_manager.h', 'socket/client_socket_pool_manager_impl.cc', 'socket/client_socket_pool_manager_impl.h', - 'socket/nss_ssl_util.cc', - 'socket/nss_ssl_util.h', 'socket/server_socket.cc', 'socket/server_socket.h', 'socket/socket_descriptor.cc', @@ -1084,13 +1063,9 @@ 'socket/socks_client_socket.h', 'socket/socks_client_socket_pool.cc', 'socket/socks_client_socket_pool.h', - 'socket/ssl_client_socket_nss.cc', - 'socket/ssl_client_socket_nss.h', 'socket/ssl_client_socket_pool.cc', 'socket/ssl_client_socket_pool.h', 'socket/ssl_server_socket.h', - 'socket/ssl_server_socket_nss.cc', - 'socket/ssl_server_socket_nss.h', 'socket/ssl_server_socket_openssl.cc', 'socket/ssl_server_socket_openssl.h', 'socket/stream_socket.cc', @@ -1213,7 +1188,6 @@ 'ssl/test_ssl_private_key.h', 'ssl/threaded_ssl_private_key.cc', 'ssl/threaded_ssl_private_key.h', - 'ssl/token_binding_nss.cc', 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', 'third_party/mozilla_security_manager/nsKeygenHandler.h', 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp', @@ -1665,7 +1639,6 @@ 'quic/test_tools/crypto_test_utils.cc', 'quic/test_tools/crypto_test_utils.h', 'quic/test_tools/crypto_test_utils_chromium.cc', - 'quic/test_tools/crypto_test_utils_nss.cc', 'quic/test_tools/crypto_test_utils_openssl.cc', 'quic/test_tools/delayed_verify_strike_register_client.cc', 'quic/test_tools/delayed_verify_strike_register_client.h',
diff --git a/net/net_common.gypi b/net/net_common.gypi index bc67032..54bd346 100644 --- a/net/net_common.gypi +++ b/net/net_common.gypi
@@ -11,6 +11,7 @@ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../crypto/crypto.gyp:crypto', '../sdch/sdch.gyp:sdch', + '../third_party/boringssl/boringssl.gyp:boringssl', '../third_party/protobuf/protobuf.gyp:protobuf_lite', '../third_party/zlib/zlib.gyp:zlib', '../url/url.gyp:url_url_features', @@ -106,110 +107,24 @@ 'dns/dns_client.cc', ], }], - ['use_openssl==1', { - 'sources!': [ - 'base/nss_memio.c', - 'base/nss_memio.h', - 'cert/ct_log_verifier_nss.cc', - 'cert/ct_objects_extractor_nss.cc', - 'cert/jwk_serializer_nss.cc', - 'cert/scoped_nss_types.h', - 'cert/x509_certificate_ios.cc', - 'cert/x509_util_nss.cc', - 'quic/crypto/aead_base_decrypter_nss.cc', - 'quic/crypto/aead_base_encrypter_nss.cc', - 'quic/crypto/aes_128_gcm_12_decrypter_nss.cc', - 'quic/crypto/aes_128_gcm_12_encrypter_nss.cc', - 'quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc', - 'quic/crypto/chacha20_poly1305_rfc7539_encrypter_nss.cc', - 'quic/crypto/channel_id_nss.cc', - 'quic/crypto/p256_key_exchange_nss.cc', - 'quic/crypto/proof_source_chromium_nss.cc', - 'socket/nss_ssl_util.cc', - 'socket/nss_ssl_util.h', - 'socket/ssl_client_socket_nss.cc', - 'socket/ssl_client_socket_nss.h', - 'socket/ssl_server_socket_nss.cc', - 'socket/ssl_server_socket_nss.h', - 'ssl/token_binding_nss.cc', - ], + [ 'use_nss_certs == 1', { 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - 'conditions': [ - ['chromecast==1 and use_nss_certs==1', { - 'sources': [ - 'ssl/ssl_platform_key_chromecast.cc', - ], - 'sources!': [ - 'ssl/ssl_platform_key_nss.cc', - ], - }], - ], - }, - { # else !use_openssl: remove the unneeded files and depend on NSS. - 'sources!': [ - 'cert/ct_log_verifier_openssl.cc', - 'cert/ct_objects_extractor_openssl.cc', - 'cert/jwk_serializer_openssl.cc', - 'cert/x509_util_openssl.cc', - 'cert/x509_util_openssl.h', - 'quic/crypto/aead_base_decrypter_openssl.cc', - 'quic/crypto/aead_base_encrypter_openssl.cc', - 'quic/crypto/aes_128_gcm_12_decrypter_openssl.cc', - 'quic/crypto/aes_128_gcm_12_encrypter_openssl.cc', - 'quic/crypto/chacha20_poly1305_rfc7539_decrypter_openssl.cc', - 'quic/crypto/chacha20_poly1305_rfc7539_encrypter_openssl.cc', - 'quic/crypto/channel_id_openssl.cc', - 'quic/crypto/p256_key_exchange_openssl.cc', - 'quic/crypto/proof_source_chromium_openssl.cc', - 'quic/crypto/scoped_evp_aead_ctx.cc', - 'quic/crypto/scoped_evp_aead_ctx.h', - 'socket/ssl_client_socket_openssl.cc', - 'socket/ssl_client_socket_openssl.h', - 'socket/ssl_server_socket_openssl.cc', - 'socket/ssl_server_socket_openssl.h', - 'ssl/client_key_store.cc', - 'ssl/client_key_store.h', - 'ssl/openssl_ssl_util.cc', - 'ssl/openssl_ssl_util.h', - 'ssl/ssl_client_session_cache_openssl.cc', - 'ssl/ssl_client_session_cache_openssl.h', - 'ssl/ssl_key_logger.cc', - 'ssl/ssl_key_logger.h', - 'ssl/ssl_platform_key.h', - 'ssl/ssl_platform_key_nss.cc', - 'ssl/ssl_platform_key_task_runner.cc', - 'ssl/ssl_platform_key_task_runner.h', - 'ssl/test_ssl_private_key.cc', - 'ssl/test_ssl_private_key.h', - 'ssl/threaded_ssl_private_key.cc', - 'ssl/threaded_ssl_private_key.h', - 'ssl/token_binding_openssl.cc', - ], - }, - ], - [ 'use_nss_verifier == 1', { - 'conditions': [ - # Pull in the bundled or system NSS as appropriate. - [ 'desktop_linux == 1 or chromeos == 1', { - 'dependencies': [ - '../build/linux/system.gyp:ssl', - ], - }, { - 'dependencies': [ - '../third_party/nss/nss.gyp:nspr', - '../third_party/nss/nss.gyp:nss', - 'third_party/nss/ssl.gyp:libssl', - ], - }] + '../build/linux/system.gyp:ssl', ], }, { 'sources!': [ 'cert/x509_util_nss.h', - ], - }, + ] + } ], + ['chromecast==1 and use_nss_certs==1', { + 'sources': [ + 'ssl/ssl_platform_key_chromecast.cc', + ], + 'sources!': [ + 'ssl/ssl_platform_key_nss.cc', + ], + }], [ 'use_openssl_certs == 0', { 'sources!': [ 'base/crypto_module_openssl.cc', @@ -260,13 +175,19 @@ '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.cc', + 'cert_net/nss_ocsp.cc', + 'cert_net/nss_ocsp.h', 'ssl/client_cert_store_nss.cc', 'ssl/client_cert_store_nss.h', 'ssl/client_key_store.cc', @@ -281,38 +202,14 @@ ], }, ], - [ 'use_nss_verifier != 1', { - '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', - ], - }, - ], # 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', { + [ 'use_nss_certs == 1', { 'sources': [ 'third_party/nss/ssl/cmpcert.c', ], }], - [ 'OS == "ios" and use_nss_verifier == 0', { - 'sources!': [ - 'cert/x509_util_ios.cc', - 'cert/x509_util_ios.h', - ], - }], - [ 'OS == "ios" and use_nss_verifier == 1', { - 'sources!': [ - 'cert/cert_verify_proc_ios.cc', - 'cert/cert_verify_proc_ios.h', - 'cert/x509_certificate_openssl_ios.cc', - ], - }], [ 'enable_websockets == 1', { 'sources': ['<@(net_websockets_sources)'] }], @@ -458,7 +355,7 @@ ['include', '^proxy/proxy_server_mac\\.cc$'], ], }], - ['OS == "ios" and <(use_nss_verifier) == 0', { + ['OS == "ios"', { 'sources/': [ ['include', '^cert/test_root_certs_mac\\.cc$'], ],
diff --git a/net/quic/crypto/aead_base_decrypter.h b/net/quic/crypto/aead_base_decrypter.h index c76f11f..715961a 100644 --- a/net/quic/crypto/aead_base_decrypter.h +++ b/net/quic/crypto/aead_base_decrypter.h
@@ -10,29 +10,17 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "net/quic/crypto/quic_decrypter.h" - -#if defined(USE_OPENSSL) #include "net/quic/crypto/scoped_evp_aead_ctx.h" -#else -#include <pkcs11t.h> -#endif namespace net { // AeadBaseDecrypter is the base class of AEAD QuicDecrypter subclasses. class NET_EXPORT_PRIVATE AeadBaseDecrypter : public QuicDecrypter { public: -#if defined(USE_OPENSSL) AeadBaseDecrypter(const EVP_AEAD* aead_alg, size_t key_size, size_t auth_tag_size, size_t nonce_prefix_size); -#else - AeadBaseDecrypter(CK_MECHANISM_TYPE aead_mechanism, - size_t key_size, - size_t auth_tag_size, - size_t nonce_prefix_size); -#endif ~AeadBaseDecrypter() override; // QuicDecrypter implementation @@ -55,27 +43,8 @@ static const size_t kMaxKeySize = 32; static const size_t kMaxNoncePrefixSize = 4; -#if !defined(USE_OPENSSL) - struct AeadParams { - unsigned int len; - union { - CK_GCM_PARAMS gcm_params; - CK_NSS_AEAD_PARAMS nss_aead_params; - } data; - }; - - virtual void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const = 0; -#endif // !defined(USE_OPENSSL) - private: -#if defined(USE_OPENSSL) const EVP_AEAD* const aead_alg_; -#else - const CK_MECHANISM_TYPE aead_mechanism_; -#endif const size_t key_size_; const size_t auth_tag_size_; const size_t nonce_prefix_size_; @@ -85,9 +54,7 @@ // The nonce prefix. unsigned char nonce_prefix_[kMaxNoncePrefixSize]; -#if defined(USE_OPENSSL) ScopedEVPAEADCtx ctx_; -#endif DISALLOW_COPY_AND_ASSIGN(AeadBaseDecrypter); };
diff --git a/net/quic/crypto/aead_base_decrypter_nss.cc b/net/quic/crypto/aead_base_decrypter_nss.cc deleted file mode 100644 index 30865e4..0000000 --- a/net/quic/crypto/aead_base_decrypter_nss.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright (c) 2013 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 <pk11pub.h> - -#include <memory> - -#include "crypto/scoped_nss_types.h" -#include "net/quic/crypto/aead_base_decrypter.h" -#include "net/quic/quic_flags.h" -#include "net/quic/quic_utils.h" - -using base::StringPiece; - -namespace net { - -AeadBaseDecrypter::AeadBaseDecrypter(CK_MECHANISM_TYPE aead_mechanism, - size_t key_size, - size_t auth_tag_size, - size_t nonce_prefix_size) - : aead_mechanism_(aead_mechanism), - key_size_(key_size), - auth_tag_size_(auth_tag_size), - nonce_prefix_size_(nonce_prefix_size) { - DCHECK_LE(key_size_, sizeof(key_)); - DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_)); -} - -AeadBaseDecrypter::~AeadBaseDecrypter() {} - -bool AeadBaseDecrypter::SetKey(StringPiece key) { - DCHECK_EQ(key.size(), key_size_); - if (key.size() != key_size_) { - return false; - } - memcpy(key_, key.data(), key.size()); - return true; -} - -bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { - DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_); - if (nonce_prefix.size() != nonce_prefix_size_) { - return false; - } - memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size()); - return true; -} - -bool AeadBaseDecrypter::DecryptPacket(QuicPathId path_id, - QuicPacketNumber packet_number, - StringPiece associated_data, - StringPiece ciphertext, - char* output, - size_t* output_length, - size_t max_output_length) { - if (ciphertext.length() < auth_tag_size_) { - return false; - } - - uint8_t nonce[sizeof(nonce_prefix_) + sizeof(packet_number)]; - const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number); - DCHECK_LE(nonce_size, sizeof(nonce)); - memcpy(nonce, nonce_prefix_, nonce_prefix_size_); - uint64_t path_id_packet_number = - QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number); - memcpy(nonce + nonce_prefix_size_, &path_id_packet_number, - sizeof(path_id_packet_number)); - - // NSS 3.14.x incorrectly requires an output buffer at least as long as - // the ciphertext (NSS bug - // https://bugzilla.mozilla.org/show_bug.cgi?id= 853674). Fortunately - // QuicDecrypter::Decrypt() specifies that |output| must be as long as - // |ciphertext| on entry. - size_t plaintext_size = ciphertext.length() - auth_tag_size_; - - // Import key_ into NSS. - SECItem key_item; - key_item.type = siBuffer; - key_item.data = key_; - key_item.len = key_size_; - PK11SlotInfo* slot = PK11_GetInternalSlot(); - - // The exact value of the |origin| argument doesn't matter to NSS as long as - // it's not PK11_OriginFortezzaHack, so pass PK11_OriginUnwrap as a - // placeholder. - crypto::ScopedPK11SymKey aead_key( - PK11_ImportSymKey(slot, aead_mechanism_, PK11_OriginUnwrap, CKA_DECRYPT, - &key_item, nullptr)); - PK11_FreeSlot(slot); - slot = nullptr; - if (!aead_key) { - DVLOG(1) << "PK11_ImportSymKey failed"; - return false; - } - - AeadParams aead_params = {0}; - FillAeadParams(StringPiece(reinterpret_cast<char*>(nonce), nonce_size), - associated_data, auth_tag_size_, &aead_params); - - SECItem param; - param.type = siBuffer; - param.data = reinterpret_cast<unsigned char*>(&aead_params.data); - param.len = aead_params.len; - - unsigned int output_len; - if (PK11_Decrypt(aead_key.get(), aead_mechanism_, ¶m, - reinterpret_cast<uint8_t*>(output), &output_len, - max_output_length, - reinterpret_cast<const unsigned char*>(ciphertext.data()), - ciphertext.length()) != SECSuccess) { - return false; - } - - if (output_len != plaintext_size) { - DVLOG(1) << "Wrong output length"; - return false; - } - *output_length = output_len; - return true; -} - -StringPiece AeadBaseDecrypter::GetKey() const { - return StringPiece(reinterpret_cast<const char*>(key_), key_size_); -} - -StringPiece AeadBaseDecrypter::GetNoncePrefix() const { - if (nonce_prefix_size_ == 0) { - return StringPiece(); - } - return StringPiece(reinterpret_cast<const char*>(nonce_prefix_), - nonce_prefix_size_); -} - -} // namespace net
diff --git a/net/quic/crypto/aead_base_encrypter.h b/net/quic/crypto/aead_base_encrypter.h index 3330189..05d996f 100644 --- a/net/quic/crypto/aead_base_encrypter.h +++ b/net/quic/crypto/aead_base_encrypter.h
@@ -10,29 +10,17 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "net/quic/crypto/quic_encrypter.h" - -#if defined(USE_OPENSSL) #include "net/quic/crypto/scoped_evp_aead_ctx.h" -#else -#include <pkcs11t.h> -#endif namespace net { // AeadBaseEncrypter is the base class of AEAD QuicEncrypter subclasses. class NET_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter { public: -#if defined(USE_OPENSSL) AeadBaseEncrypter(const EVP_AEAD* aead_alg, size_t key_size, size_t auth_tag_size, size_t nonce_prefix_size); -#else - AeadBaseEncrypter(CK_MECHANISM_TYPE aead_mechanism, - size_t key_size, - size_t auth_tag_size, - size_t nonce_prefix_size); -#endif ~AeadBaseEncrypter() override; // QuicEncrypter implementation @@ -66,27 +54,8 @@ static const size_t kMaxKeySize = 32; static const size_t kMaxNoncePrefixSize = 4; -#if !defined(USE_OPENSSL) - struct AeadParams { - unsigned int len; - union { - CK_GCM_PARAMS gcm_params; - CK_NSS_AEAD_PARAMS nss_aead_params; - } data; - }; - - virtual void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const = 0; -#endif - private: -#if defined(USE_OPENSSL) const EVP_AEAD* const aead_alg_; -#else - const CK_MECHANISM_TYPE aead_mechanism_; -#endif const size_t key_size_; const size_t auth_tag_size_; const size_t nonce_prefix_size_; @@ -96,9 +65,7 @@ // The nonce prefix. unsigned char nonce_prefix_[kMaxNoncePrefixSize]; -#if defined(USE_OPENSSL) ScopedEVPAEADCtx ctx_; -#endif DISALLOW_COPY_AND_ASSIGN(AeadBaseEncrypter); };
diff --git a/net/quic/crypto/aead_base_encrypter_nss.cc b/net/quic/crypto/aead_base_encrypter_nss.cc deleted file mode 100644 index cfb6e79e..0000000 --- a/net/quic/crypto/aead_base_encrypter_nss.cc +++ /dev/null
@@ -1,178 +0,0 @@ -// Copyright (c) 2013 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 <pk11pub.h> - -#include <memory> - -#include "crypto/scoped_nss_types.h" -#include "net/quic/crypto/aead_base_encrypter.h" -#include "net/quic/quic_flags.h" -#include "net/quic/quic_utils.h" - -using base::StringPiece; - -namespace net { - -namespace { - -// The maximum size in bytes of the nonce, including 8 bytes of sequence number. -// ChaCha20 uses only the 8 byte sequence number and AES-GCM uses 12 bytes. -const size_t kMaxNonceSize = 12; - -} // namespace - -AeadBaseEncrypter::AeadBaseEncrypter(CK_MECHANISM_TYPE aead_mechanism, - size_t key_size, - size_t auth_tag_size, - size_t nonce_prefix_size) - : aead_mechanism_(aead_mechanism), - key_size_(key_size), - auth_tag_size_(auth_tag_size), - nonce_prefix_size_(nonce_prefix_size) { - DCHECK_LE(key_size_, sizeof(key_)); - DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_)); - DCHECK_GE(kMaxNonceSize, nonce_prefix_size_); -} - -AeadBaseEncrypter::~AeadBaseEncrypter() {} - -bool AeadBaseEncrypter::SetKey(StringPiece key) { - DCHECK_EQ(key.size(), key_size_); - if (key.size() != key_size_) { - return false; - } - memcpy(key_, key.data(), key.size()); - return true; -} - -bool AeadBaseEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { - DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_); - if (nonce_prefix.size() != nonce_prefix_size_) { - return false; - } - memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size()); - return true; -} - -bool AeadBaseEncrypter::Encrypt(StringPiece nonce, - StringPiece associated_data, - StringPiece plaintext, - unsigned char* output) { - if (nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketNumber)) { - return false; - } - - size_t ciphertext_size = GetCiphertextSize(plaintext.length()); - - // Import key_ into NSS. - SECItem key_item; - key_item.type = siBuffer; - key_item.data = key_; - key_item.len = key_size_; - PK11SlotInfo* slot = PK11_GetInternalSlot(); - - // The exact value of the |origin| argument doesn't matter to NSS as long as - // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a - // placeholder. - crypto::ScopedPK11SymKey aead_key( - PK11_ImportSymKey(slot, aead_mechanism_, PK11_OriginUnwrap, CKA_ENCRYPT, - &key_item, nullptr)); - PK11_FreeSlot(slot); - slot = nullptr; - if (!aead_key) { - DVLOG(1) << "PK11_ImportSymKey failed"; - return false; - } - - AeadParams aead_params = {0}; - FillAeadParams(nonce, associated_data, auth_tag_size_, &aead_params); - - SECItem param; - param.type = siBuffer; - param.data = reinterpret_cast<unsigned char*>(&aead_params.data); - param.len = aead_params.len; - - if (plaintext.size() > kMaxPacketSize) { - DLOG(FATAL) << "Plaintext too large"; - return false; - } - // NSS doesn't support inplace encryption, so copy plaintext to a temporary - // buffer. - unsigned char temp_plaintext[kMaxPacketSize]; - memcpy(temp_plaintext, plaintext.data(), plaintext.size()); - - unsigned int output_len; - if (PK11_Encrypt(aead_key.get(), aead_mechanism_, ¶m, output, &output_len, - ciphertext_size, temp_plaintext, - plaintext.size()) != SECSuccess) { - DVLOG(1) << "PK11_Encrypt failed"; - return false; - } - - if (output_len != ciphertext_size) { - DVLOG(1) << "Wrong output length"; - return false; - } - - return true; -} - -bool AeadBaseEncrypter::EncryptPacket(QuicPathId path_id, - QuicPacketNumber packet_number, - StringPiece associated_data, - StringPiece plaintext, - char* output, - size_t* output_length, - size_t max_output_length) { - size_t ciphertext_size = GetCiphertextSize(plaintext.length()); - if (max_output_length < ciphertext_size) { - return false; - } - // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the - // same packet number twice. - const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number); - ALIGNAS(4) char nonce_buffer[kMaxNonceSize]; - memcpy(nonce_buffer, nonce_prefix_, nonce_prefix_size_); - uint64_t path_id_packet_number = - QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number); - memcpy(nonce_buffer + nonce_prefix_size_, &path_id_packet_number, - sizeof(path_id_packet_number)); - if (!Encrypt(StringPiece(nonce_buffer, nonce_size), associated_data, - plaintext, reinterpret_cast<unsigned char*>(output))) { - return false; - } - *output_length = ciphertext_size; - return true; -} - -size_t AeadBaseEncrypter::GetKeySize() const { - return key_size_; -} - -size_t AeadBaseEncrypter::GetNoncePrefixSize() const { - return nonce_prefix_size_; -} - -size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { - return ciphertext_size - auth_tag_size_; -} - -size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const { - return plaintext_size + auth_tag_size_; -} - -StringPiece AeadBaseEncrypter::GetKey() const { - return StringPiece(reinterpret_cast<const char*>(key_), key_size_); -} - -StringPiece AeadBaseEncrypter::GetNoncePrefix() const { - if (nonce_prefix_size_ == 0) { - return StringPiece(); - } - return StringPiece(reinterpret_cast<const char*>(nonce_prefix_), - nonce_prefix_size_); -} - -} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter.h b/net/quic/crypto/aes_128_gcm_12_decrypter.h index f8b1196..5883c76f 100644 --- a/net/quic/crypto/aes_128_gcm_12_decrypter.h +++ b/net/quic/crypto/aes_128_gcm_12_decrypter.h
@@ -29,15 +29,6 @@ Aes128Gcm12Decrypter(); ~Aes128Gcm12Decrypter() override; -#if !defined(USE_OPENSSL) - protected: - // AeadBaseDecrypter methods: - void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const override; -#endif - const char* cipher_name() const override; uint32_t cipher_id() const override;
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc deleted file mode 100644 index d4480f4..0000000 --- a/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright (c) 2013 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 "net/quic/crypto/aes_128_gcm_12_decrypter.h" - -#include <pk11pub.h> -#include <secerr.h> - -using base::StringPiece; - -namespace net { - -namespace { - -const size_t kKeySize = 16; -const size_t kNoncePrefixSize = 4; - -} // namespace - -Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() - : AeadBaseDecrypter(CKM_AES_GCM, kKeySize, kAuthTagSize, kNoncePrefixSize) { - static_assert(kKeySize <= kMaxKeySize, "key size too big"); - static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize, - "nonce prefix size too big"); -} - -Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {} - -void Aes128Gcm12Decrypter::FillAeadParams(StringPiece nonce, - StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const { - aead_params->len = sizeof(aead_params->data.gcm_params); - CK_GCM_PARAMS* gcm_params = &aead_params->data.gcm_params; - gcm_params->pIv = reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data())); - gcm_params->ulIvLen = nonce.size(); - gcm_params->pAAD = - reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data())); - gcm_params->ulAADLen = associated_data.size(); - gcm_params->ulTagBits = auth_tag_size * 8; -} - -const char* Aes128Gcm12Decrypter::cipher_name() const { - // TODO(rtenneti): Use TLS1_TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 instead - // of hard coded string. - // return TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256; - return "ECDHE-RSA-AES128-GCM-SHA256"; -} - -uint32_t Aes128Gcm12Decrypter::cipher_id() const { - // TODO(rtenneti): when Chromium requires NSS 3.15.2 or later, use - // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 instead of 0xC02F. - // Or'ed with 0x03000000 to match OpenSSL/BoringSSL implementations. - return 0x03000000 | 0xC02F; -} - -} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter.h b/net/quic/crypto/aes_128_gcm_12_encrypter.h index f2f7b41..3af151e1 100644 --- a/net/quic/crypto/aes_128_gcm_12_encrypter.h +++ b/net/quic/crypto/aes_128_gcm_12_encrypter.h
@@ -28,15 +28,6 @@ Aes128Gcm12Encrypter(); ~Aes128Gcm12Encrypter() override; -#if !defined(USE_OPENSSL) - protected: - // AeadBaseEncrypter methods: - void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const override; -#endif - private: DISALLOW_COPY_AND_ASSIGN(Aes128Gcm12Encrypter); };
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc deleted file mode 100644 index 78c1d3dc..0000000 --- a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2013 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 "net/quic/crypto/aes_128_gcm_12_encrypter.h" - -#include <pk11pub.h> -#include <secerr.h> - -using base::StringPiece; - -namespace net { - -namespace { - -const size_t kKeySize = 16; -const size_t kNoncePrefixSize = 4; - -} // namespace - -Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() - : AeadBaseEncrypter(CKM_AES_GCM, kKeySize, kAuthTagSize, kNoncePrefixSize) { - static_assert(kKeySize <= kMaxKeySize, "key size too big"); - static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize, - "nonce prefix size too big"); -} - -Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {} - -void Aes128Gcm12Encrypter::FillAeadParams(StringPiece nonce, - StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const { - aead_params->len = sizeof(aead_params->data.gcm_params); - CK_GCM_PARAMS* gcm_params = &aead_params->data.gcm_params; - gcm_params->pIv = reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data())); - gcm_params->ulIvLen = nonce.size(); - gcm_params->pAAD = - reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data())); - gcm_params->ulAADLen = associated_data.size(); - gcm_params->ulTagBits = auth_tag_size * 8; -} - -} // namespace net
diff --git a/net/quic/crypto/chacha20_poly1305_decrypter.h b/net/quic/crypto/chacha20_poly1305_decrypter.h index 1e0fd05f..a75556e 100644 --- a/net/quic/crypto/chacha20_poly1305_decrypter.h +++ b/net/quic/crypto/chacha20_poly1305_decrypter.h
@@ -30,15 +30,6 @@ ChaCha20Poly1305Decrypter(); ~ChaCha20Poly1305Decrypter() override; -#if !defined(USE_OPENSSL) - protected: - // AeadBaseDecrypter methods: - void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const override; -#endif - const char* cipher_name() const override; uint32_t cipher_id() const override;
diff --git a/net/quic/crypto/chacha20_poly1305_encrypter.h b/net/quic/crypto/chacha20_poly1305_encrypter.h index dfdfffe..eb4afdde 100644 --- a/net/quic/crypto/chacha20_poly1305_encrypter.h +++ b/net/quic/crypto/chacha20_poly1305_encrypter.h
@@ -29,15 +29,6 @@ ChaCha20Poly1305Encrypter(); ~ChaCha20Poly1305Encrypter() override; -#if !defined(USE_OPENSSL) - protected: - // AeadBaseEncrypter methods: - void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const override; -#endif - private: DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Encrypter); };
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h index 57609d0..dc30bed0 100644 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h +++ b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h
@@ -38,15 +38,6 @@ const char* cipher_name() const override; uint32_t cipher_id() const override; -#if !defined(USE_OPENSSL) - protected: - // AeadBaseDecrypter methods: - void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const override; -#endif - private: DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Rfc7539Decrypter); };
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc deleted file mode 100644 index 799a2c5a..0000000 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2014 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 "net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h" - -#include <pk11pub.h> - -using base::StringPiece; - -namespace net { - -namespace { - -const size_t kKeySize = 32; -const size_t kNoncePrefixSize = 4; - -} // namespace - -ChaCha20Poly1305Rfc7539Decrypter::ChaCha20Poly1305Rfc7539Decrypter() - : AeadBaseDecrypter(CKM_NSS_CHACHA20_POLY1305, - kKeySize, - kAuthTagSize, - kNoncePrefixSize) { - static_assert(kKeySize <= kMaxKeySize, "key size too big"); - static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize, - "nonce prefix size too big"); -} - -ChaCha20Poly1305Rfc7539Decrypter::~ChaCha20Poly1305Rfc7539Decrypter() {} - -bool ChaCha20Poly1305Rfc7539Decrypter::IsSupported() { - return false; -} - -const char* ChaCha20Poly1305Rfc7539Decrypter::cipher_name() const { - return ""; -} - -uint32_t ChaCha20Poly1305Rfc7539Decrypter::cipher_id() const { - return 0; -} - -void ChaCha20Poly1305Rfc7539Decrypter::FillAeadParams( - base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const {} - -} // namespace net
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter.h b/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter.h index 7b6e0b4..36b1a62 100644 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter.h +++ b/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter.h
@@ -33,15 +33,6 @@ // variant of ChaCha20+Poly1305. static bool IsSupported(); -#if !defined(USE_OPENSSL) - protected: - // AeadBaseEncrypter methods: - void FillAeadParams(base::StringPiece nonce, - base::StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const override; -#endif - private: DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Rfc7539Encrypter); };
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_nss.cc b/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_nss.cc deleted file mode 100644 index 34b404ef..0000000 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_nss.cc +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2014 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 "net/quic/crypto/chacha20_poly1305_rfc7539_encrypter.h" - -#include <pk11pub.h> - -using base::StringPiece; - -namespace net { - -namespace { - -const size_t kKeySize = 32; -const size_t kNoncePrefixSize = 4; - -} // namespace - -ChaCha20Poly1305Rfc7539Encrypter::ChaCha20Poly1305Rfc7539Encrypter() - : AeadBaseEncrypter(CKM_NSS_CHACHA20_POLY1305, - kKeySize, - kAuthTagSize, - kNoncePrefixSize) { - static_assert(kKeySize <= kMaxKeySize, "key size too big"); - static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize, - "nonce prefix size too big"); -} - -ChaCha20Poly1305Rfc7539Encrypter::~ChaCha20Poly1305Rfc7539Encrypter() {} - -bool ChaCha20Poly1305Rfc7539Encrypter::IsSupported() { - return false; -} - -void ChaCha20Poly1305Rfc7539Encrypter::FillAeadParams( - StringPiece nonce, - StringPiece associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const {} - -} // namespace net
diff --git a/net/quic/crypto/channel_id_nss.cc b/net/quic/crypto/channel_id_nss.cc deleted file mode 100644 index 522b2f6..0000000 --- a/net/quic/crypto/channel_id_nss.cc +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2013 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 "net/quic/crypto/channel_id.h" - -#include <keythi.h> -#include <pk11pub.h> -#include <sechash.h> - -using base::StringPiece; - -namespace net { - -// static -bool ChannelIDVerifier::Verify(StringPiece key, - StringPiece signed_data, - StringPiece signature) { - return VerifyRaw(key, signed_data, signature, true); -} - -// static -bool ChannelIDVerifier::VerifyRaw(StringPiece key, - StringPiece signed_data, - StringPiece signature, - bool is_channel_id_signature) { - if (key.size() != 32 * 2 || signature.size() != 32 * 2) { - return false; - } - - SECKEYPublicKey public_key; - memset(&public_key, 0, sizeof(public_key)); - - // DER encoding of the object identifier (OID) of the named curve P-256 - // (1.2.840.10045.3.1.7). See RFC 6637 Section 11. - static const unsigned char p256_oid[] = {0x06, 0x08, 0x2a, 0x86, 0x48, - 0xce, 0x3d, 0x03, 0x01, 0x07}; - public_key.keyType = ecKey; - public_key.u.ec.DEREncodedParams.type = siBuffer; - public_key.u.ec.DEREncodedParams.data = const_cast<unsigned char*>(p256_oid); - public_key.u.ec.DEREncodedParams.len = sizeof(p256_oid); - - unsigned char key_buf[65]; - key_buf[0] = 0x04; - memcpy(&key_buf[1], key.data(), key.size()); - public_key.u.ec.publicValue.type = siBuffer; - public_key.u.ec.publicValue.data = key_buf; - public_key.u.ec.publicValue.len = sizeof(key_buf); - - SECItem signature_item = {siBuffer, reinterpret_cast<unsigned char*>( - const_cast<char*>(signature.data())), - static_cast<unsigned int>(signature.size())}; - - unsigned char hash_buf[SHA256_LENGTH]; - SECItem hash_item = {siBuffer, hash_buf, sizeof(hash_buf)}; - - HASHContext* sha256 = HASH_Create(HASH_AlgSHA256); - if (!sha256) { - return false; - } - HASH_Begin(sha256); - if (is_channel_id_signature) { - HASH_Update(sha256, reinterpret_cast<const unsigned char*>(kContextStr), - strlen(kContextStr) + 1); - HASH_Update(sha256, - reinterpret_cast<const unsigned char*>(kClientToServerStr), - strlen(kClientToServerStr) + 1); - } - HASH_Update(sha256, - reinterpret_cast<const unsigned char*>(signed_data.data()), - signed_data.size()); - HASH_End(sha256, hash_buf, &hash_item.len, sizeof(hash_buf)); - HASH_Destroy(sha256); - - return PK11_Verify(&public_key, &signature_item, &hash_item, nullptr) == - SECSuccess; -} - -} // namespace net
diff --git a/net/quic/crypto/p256_key_exchange.h b/net/quic/crypto/p256_key_exchange.h index fcdc19dd..db3e404e 100644 --- a/net/quic/crypto/p256_key_exchange.h +++ b/net/quic/crypto/p256_key_exchange.h
@@ -12,16 +12,11 @@ #include "base/macros.h" #include "base/strings/string_piece.h" +#include "crypto/openssl_util.h" +#include "crypto/scoped_openssl_types.h" #include "net/base/net_export.h" #include "net/quic/crypto/key_exchange.h" -#if defined(USE_OPENSSL) -#include "crypto/openssl_util.h" -#include "crypto/scoped_openssl_types.h" -#else -#include "crypto/ec_private_key.h" -#include "crypto/scoped_nss_types.h" -#endif namespace net { @@ -59,19 +54,11 @@ kUncompressedECPointForm = 0x04, }; -#if defined(USE_OPENSSL) // P256KeyExchange takes ownership of |private_key|, and expects // |public_key| consists of |kUncompressedP256PointBytes| bytes. P256KeyExchange(EC_KEY* private_key, const uint8_t* public_key); crypto::ScopedEC_KEY private_key_; -#else - // P256KeyExchange takes ownership of |key_pair|, and expects - // |public_key| consists of |kUncompressedP256PointBytes| bytes. - P256KeyExchange(crypto::ECPrivateKey* key_pair, const uint8_t* public_key); - - std::unique_ptr<crypto::ECPrivateKey> key_pair_; -#endif // The public key stored as an uncompressed P-256 point. uint8_t public_key_[kUncompressedP256PointBytes];
diff --git a/net/quic/crypto/p256_key_exchange_nss.cc b/net/quic/crypto/p256_key_exchange_nss.cc deleted file mode 100644 index 8c28e53..0000000 --- a/net/quic/crypto/p256_key_exchange_nss.cc +++ /dev/null
@@ -1,225 +0,0 @@ -// Copyright (c) 2013 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 "net/quic/crypto/p256_key_exchange.h" - -#include "base/logging.h" -#include "base/numerics/safe_conversions.h" -#include "base/sys_byteorder.h" - -using base::StringPiece; -using std::string; -using std::vector; - -namespace net { - -namespace { - -// Password used by |NewPrivateKey| to encrypt exported EC private keys. -// This is not used to provide any security, but to workaround NSS being -// unwilling to export unencrypted EC keys. Note that SPDY and ChannelID -// use the same approach. -const char kExportPassword[] = ""; - -// Convert StringPiece to vector of uint8_t. -static vector<uint8_t> StringPieceToVector(StringPiece piece) { - return vector<uint8_t>(piece.data(), piece.data() + piece.length()); -} - -} // namespace - -P256KeyExchange::P256KeyExchange(crypto::ECPrivateKey* key_pair, - const uint8_t* public_key) - : key_pair_(key_pair) { - memcpy(public_key_, public_key, sizeof(public_key_)); -} - -P256KeyExchange::~P256KeyExchange() {} - -// static -P256KeyExchange* P256KeyExchange::New(StringPiece key) { - if (key.size() < 2) { - DVLOG(1) << "Key pair is too small."; - return nullptr; - } - - const uint8_t* data = reinterpret_cast<const uint8_t*>(key.data()); - size_t size = - static_cast<size_t>(data[0]) | (static_cast<size_t>(data[1]) << 8); - key.remove_prefix(2); - if (key.size() < size) { - DVLOG(1) << "Key pair does not contain key material."; - return nullptr; - } - - StringPiece private_piece(key.data(), size); - key.remove_prefix(size); - if (key.empty()) { - DVLOG(1) << "Key pair does not contain public key."; - return nullptr; - } - - StringPiece public_piece(key); - - std::unique_ptr<crypto::ECPrivateKey> key_pair( - crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - kExportPassword, - // TODO(thaidn): fix this interface to avoid copying secrets. - StringPieceToVector(private_piece), - StringPieceToVector(public_piece))); - - if (!key_pair.get()) { - DVLOG(1) << "Can't decrypt private key."; - return nullptr; - } - - // Perform some sanity checks on the public key. - SECKEYPublicKey* public_key = key_pair->public_key(); - if (public_key->keyType != ecKey || - public_key->u.ec.publicValue.len != kUncompressedP256PointBytes || - !public_key->u.ec.publicValue.data || - public_key->u.ec.publicValue.data[0] != kUncompressedECPointForm) { - DVLOG(1) << "Key is invalid."; - return nullptr; - } - - // Ensure that the key is using the correct curve, i.e., NIST P-256. - const SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); - if (!oid_data) { - DVLOG(1) << "Can't get P-256's OID."; - return nullptr; - } - - if (public_key->u.ec.DEREncodedParams.len != oid_data->oid.len + 2 || - !public_key->u.ec.DEREncodedParams.data || - public_key->u.ec.DEREncodedParams.data[0] != SEC_ASN1_OBJECT_ID || - public_key->u.ec.DEREncodedParams.data[1] != oid_data->oid.len || - memcmp(public_key->u.ec.DEREncodedParams.data + 2, oid_data->oid.data, - oid_data->oid.len) != 0) { - DVLOG(1) << "Key is invalid."; - } - - return new P256KeyExchange(key_pair.release(), - public_key->u.ec.publicValue.data); -} - -// static -string P256KeyExchange::NewPrivateKey() { - std::unique_ptr<crypto::ECPrivateKey> key_pair( - crypto::ECPrivateKey::Create()); - - if (!key_pair.get()) { - DVLOG(1) << "Can't generate new key pair."; - return string(); - } - - vector<uint8_t> private_key; - if (!key_pair->ExportEncryptedPrivateKey(kExportPassword, 1 /* iteration */, - &private_key)) { - DVLOG(1) << "Can't export private key."; - return string(); - } - - // NSS lacks the ability to import an ECC private key without - // also importing the public key, so it is necessary to also - // store the public key. - vector<uint8_t> public_key; - if (!key_pair->ExportPublicKey(&public_key)) { - DVLOG(1) << "Can't export public key."; - return string(); - } - - // TODO(thaidn): determine how large encrypted private key can be - uint16_t private_key_size = base::checked_cast<uint16_t>(private_key.size()); - const size_t result_size = - sizeof(private_key_size) + private_key_size + public_key.size(); - vector<char> result(result_size); - char* resultp = &result[0]; - // Export the key string. - // The first two bytes are the private key's size in little endian. - private_key_size = base::ByteSwapToLE16(private_key_size); - memcpy(resultp, &private_key_size, sizeof(private_key_size)); - resultp += sizeof(private_key_size); - memcpy(resultp, &private_key[0], private_key.size()); - resultp += private_key.size(); - memcpy(resultp, &public_key[0], public_key.size()); - - return string(&result[0], result_size); -} - -KeyExchange* P256KeyExchange::NewKeyPair(QuicRandom* /*rand*/) const { - // TODO(agl): avoid the serialisation/deserialisation in this function. - const string private_value = NewPrivateKey(); - return P256KeyExchange::New(private_value); -} - -bool P256KeyExchange::CalculateSharedKey(StringPiece peer_public_value, - string* out_result) const { - if (peer_public_value.size() != kUncompressedP256PointBytes || - peer_public_value[0] != kUncompressedECPointForm) { - DVLOG(1) << "Peer public value is invalid."; - return false; - } - - DCHECK(key_pair_.get()); - DCHECK(key_pair_->public_key()); - - SECKEYPublicKey peer_public_key; - memset(&peer_public_key, 0, sizeof(peer_public_key)); - - peer_public_key.keyType = ecKey; - // Both sides of a ECDH key exchange need to use the same EC params. - peer_public_key.u.ec.DEREncodedParams.len = - key_pair_->public_key()->u.ec.DEREncodedParams.len; - peer_public_key.u.ec.DEREncodedParams.data = - key_pair_->public_key()->u.ec.DEREncodedParams.data; - - peer_public_key.u.ec.publicValue.type = siBuffer; - peer_public_key.u.ec.publicValue.data = - reinterpret_cast<uint8_t*>(const_cast<char*>(peer_public_value.data())); - peer_public_key.u.ec.publicValue.len = peer_public_value.size(); - - // The NSS function performing ECDH key exchange is PK11_PubDeriveWithKDF. - // As this function is used for SSL/TLS's ECDH key exchanges it has many - // arguments, most of which are not required in QUIC. - // Key derivation function CKD_NULL is used because the return value of - // |CalculateSharedKey| is the actual ECDH shared key, not any derived keys - // from it. - crypto::ScopedPK11SymKey premaster_secret( - PK11_PubDeriveWithKDF(key_pair_->key(), &peer_public_key, PR_FALSE, - nullptr, nullptr, CKM_ECDH1_DERIVE, /* mechanism */ - CKM_GENERIC_SECRET_KEY_GEN, /* target */ - CKA_DERIVE, 0, CKD_NULL, /* kdf */ - nullptr, nullptr)); - - if (!premaster_secret.get()) { - DVLOG(1) << "Can't derive ECDH shared key."; - return false; - } - - if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) { - DVLOG(1) << "Can't extract raw ECDH shared key."; - return false; - } - - SECItem* key_data = PK11_GetKeyData(premaster_secret.get()); - if (!key_data || !key_data->data || key_data->len != kP256FieldBytes) { - DVLOG(1) << "ECDH shared key is invalid."; - return false; - } - - out_result->assign(reinterpret_cast<char*>(key_data->data), key_data->len); - return true; -} - -StringPiece P256KeyExchange::public_value() const { - return StringPiece(reinterpret_cast<const char*>(public_key_), - sizeof(public_key_)); -} - -QuicTag P256KeyExchange::tag() const { - return kP256; -} - -} // namespace net
diff --git a/net/quic/crypto/proof_source_chromium_nss.cc b/net/quic/crypto/proof_source_chromium_nss.cc deleted file mode 100644 index 8ab7cc3..0000000 --- a/net/quic/crypto/proof_source_chromium_nss.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2013 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 "net/quic/crypto/proof_source_chromium.h" - -using std::string; -using std::vector; - -namespace net { - -ProofSourceChromium::ProofSourceChromium() {} - -ProofSourceChromium::~ProofSourceChromium() {} - -bool ProofSourceChromium::Initialize(const base::FilePath& cert_path, - const base::FilePath& key_path, - const base::FilePath& sct_path) { - return false; -} - -bool ProofSourceChromium::GetProof(const IPAddress& server_ip, - const string& hostname, - const string& server_config, - QuicVersion quic_version, - base::StringPiece chlo_hash, - bool ecdsa_ok, - scoped_refptr<ProofSource::Chain>* out_chain, - string* out_signature, - string* out_leaf_cert_sct) { - return false; -} - -} // namespace net
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index f937857..effc787 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include <memory> +#include <string> +#include <utility> #include <vector> #include "base/compiler_specific.h" @@ -287,7 +289,7 @@ QuicPacketNumber largest_received, QuicPacketNumber least_unacked, QuicErrorCode quic_error, - std::string& quic_error_details) { + const std::string& quic_error_details) { return maker_.MakeAckAndConnectionClosePacket( num, false, delta_time_largest_observed, largest_received, least_unacked, quic_error, quic_error_details); @@ -305,15 +307,15 @@ SpdyHeaderBlock GetRequestHeaders(const std::string& method, const std::string& scheme, const std::string& path) { - return GetRequestHeaders(method, scheme, path, maker_); + return GetRequestHeaders(method, scheme, path, &maker_); } // Uses customized QuicTestPacketMaker. SpdyHeaderBlock GetRequestHeaders(const std::string& method, const std::string& scheme, const std::string& path, - QuicTestPacketMaker& maker) { - return maker.GetRequestHeaders(method, scheme, path); + QuicTestPacketMaker* maker) { + return maker->GetRequestHeaders(method, scheme, path); } SpdyHeaderBlock GetResponseHeaders(const std::string& status) { @@ -434,13 +436,11 @@ packet_number, stream_id, should_include_version, fin, headers, offset); } - void CreateSession() { CreateSessionWithFactory(&socket_factory_); } - - void CreateSessionWithFactory(ClientSocketFactory* socket_factory) { + void CreateSession() { params_.enable_quic = true; params_.quic_clock = clock_; params_.quic_random = &random_generator_; - params_.client_socket_factory = socket_factory; + params_.client_socket_factory = &socket_factory_; params_.quic_crypto_client_stream_factory = &crypto_client_stream_factory_; params_.host_resolver = &host_resolver_; params_.cert_verifier = &cert_verifier_; @@ -1269,7 +1269,7 @@ // Second QUIC request data. mock_quic_data.AddWrite(ConstructRequestHeadersPacket( 3, kClientDataStreamId2, false, true, - GetRequestHeaders("GET", "https", "/", maker), &request_header_offset, + GetRequestHeaders("GET", "https", "/", &maker), &request_header_offset, &maker)); mock_quic_data.AddRead(ConstructResponseHeadersPacket( 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"), @@ -1363,7 +1363,7 @@ // First QUIC request data. mock_quic_data2.AddWrite(ConstructRequestHeadersPacket( 1, kClientDataStreamId1, true, true, - GetRequestHeaders("GET", "https", "/", maker), &maker)); + GetRequestHeaders("GET", "https", "/", &maker), &maker)); mock_quic_data2.AddRead( ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"), &maker)); @@ -1804,12 +1804,10 @@ MockRead(SYNCHRONOUS, 4, kQuicAlternateProtocolHeader), MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)}; - MockClientSocketFactory socket_factory; - SequencedSocketData http_data(http_reads, arraysize(http_reads), http_writes, arraysize(http_writes)); - socket_factory.AddSocketDataProvider(&http_data); - socket_factory.AddSSLSocketDataProvider(&ssl_data_); + socket_factory_.AddSocketDataProvider(&http_data); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); // The QUIC transaction will not be allowed to complete. MockWrite quic_writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)}; @@ -1818,15 +1816,15 @@ }; SequencedSocketData quic_data(quic_reads, arraysize(quic_reads), quic_writes, arraysize(quic_writes)); - socket_factory.AddSocketDataProvider(&quic_data); + socket_factory_.AddSocketDataProvider(&quic_data); // The HTTP transaction will complete. SequencedSocketData http_data2(http_reads, arraysize(http_reads), http_writes, arraysize(http_writes)); - socket_factory.AddSocketDataProvider(&http_data2); - socket_factory.AddSSLSocketDataProvider(&ssl_data_); + socket_factory_.AddSocketDataProvider(&http_data2); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); - CreateSessionWithFactory(&socket_factory); + CreateSession(); // Run the first request. SendRequestAndExpectHttpResponse("hello world");
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index ee04541e..ba1750e 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -5,9 +5,10 @@ #include "net/quic/quic_stream_factory.h" #include <algorithm> -#include <set> #include <utility> +#include <openssl/aead.h> + #include "base/location.h" #include "base/macros.h" #include "base/memory/ptr_util.h" @@ -22,6 +23,7 @@ #include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "base/values.h" +#include "crypto/openssl_util.h" #include "net/base/ip_address.h" #include "net/base/net_errors.h" #include "net/base/socket_performance_watcher.h" @@ -58,13 +60,6 @@ #include "base/win/windows_version.h" #endif -#if defined(USE_OPENSSL) -#include <openssl/aead.h> -#include "crypto/openssl_util.h" -#else -#include "base/cpu.h" -#endif - using std::min; using std::vector; using NetworkHandle = net::NetworkChangeNotifier::NetworkHandle; @@ -384,12 +379,12 @@ const int kMaxLoadServerInfoTimeoutMs = 50; // Wait for DiskCache a maximum of 50ms. int64_t load_server_info_timeout_ms = - min(static_cast<int>( - (factory_->load_server_info_timeout_srtt_multiplier_ * - factory_->GetServerNetworkStatsSmoothedRttInMicroseconds( - server_id_)) / - 1000), - kMaxLoadServerInfoTimeoutMs); + std::min(static_cast<int>( + (factory_->load_server_info_timeout_srtt_multiplier_ * + factory_->GetServerNetworkStatsSmoothedRttInMicroseconds( + server_id_)) / + 1000), + kMaxLoadServerInfoTimeoutMs); if (load_server_info_timeout_ms > 0) { factory_->task_runner_->PostDelayedTask( FROM_HERE, @@ -681,13 +676,8 @@ } if (enable_token_binding && channel_id_service && IsTokenBindingSupported()) crypto_config_.tb_key_params.push_back(kP256); -#if defined(USE_OPENSSL) crypto::EnsureOpenSSLInit(); bool has_aes_hardware_support = !!EVP_has_aes_hardware(); -#else - base::CPU cpu; - bool has_aes_hardware_support = cpu.has_aesni() && cpu.has_avx(); -#endif UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm", has_aes_hardware_support); if (has_aes_hardware_support || prefer_aes_) @@ -766,8 +756,7 @@ quic_server_info_factory_.reset(quic_server_info_factory); } -bool QuicStreamFactory::CanUseExistingSession(QuicServerId server_id, - PrivacyMode privacy_mode, +bool QuicStreamFactory::CanUseExistingSession(const QuicServerId& server_id, StringPiece origin_host) { // TODO(zhongyi): delete active_sessions_.empty() checks once the // android crash issue(crbug.com/498823) is resolved. @@ -777,7 +766,7 @@ if (it == active_sessions_.end()) return false; QuicChromiumClientSession* session = it->second; - return session->CanPool(origin_host.as_string(), privacy_mode); + return session->CanPool(origin_host.as_string(), server_id.privacy_mode()); } int QuicStreamFactory::Create(const HostPortPair& host_port_pair, @@ -1722,7 +1711,7 @@ // touches quic_server_info_map. const QuicServerInfoMap& quic_server_info_map = http_server_properties_->quic_server_info_map(); - vector<QuicServerId> server_list(quic_server_info_map.size()); + std::vector<QuicServerId> server_list(quic_server_info_map.size()); for (const auto& key_value : quic_server_info_map) server_list.push_back(key_value.first); for (auto it = server_list.rbegin(); it != server_list.rend(); ++it) {
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index c7f10d1..1500d4a 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h
@@ -36,6 +36,7 @@ #include "net/quic/quic_crypto_stream.h" #include "net/quic/quic_http_stream.h" #include "net/quic/quic_protocol.h" +#include "net/quic/quic_server_id.h" #include "net/ssl/ssl_config_service.h" namespace net { @@ -52,7 +53,6 @@ class QuicChromiumConnectionHelper; class QuicCryptoClientStreamFactory; class QuicRandom; -class QuicServerId; class QuicServerInfo; class QuicServerInfoFactory; class QuicStreamFactory; @@ -108,7 +108,6 @@ QuicStreamFactory* factory_; HostPortPair host_port_pair_; std::string origin_host_; - std::string url_; PrivacyMode privacy_mode_; BoundNetLog net_log_; CompletionCallback callback_; @@ -168,8 +167,7 @@ // Returns true if there is an existing session to |server_id| which can be // used for request to |origin_host|. - bool CanUseExistingSession(QuicServerId server_id, - PrivacyMode privacy_mode, + bool CanUseExistingSession(const QuicServerId& server_id, StringPiece origin_host); // Creates a new QuicHttpStream to |host_port_pair| which will be
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 794e40af21..c08de4aa 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -90,11 +90,11 @@ return params; } -} // namespace anonymous +} // namespace class MockQuicServerInfo : public QuicServerInfo { public: - MockQuicServerInfo(const QuicServerId& server_id) + explicit MockQuicServerInfo(const QuicServerId& server_id) : QuicServerInfo(server_id) {} ~MockQuicServerInfo() override {} @@ -280,10 +280,15 @@ host_port_pair); } + QuicChromiumClientSession* GetActiveSession( + const HostPortPair& host_port_pair) { + return QuicStreamFactoryPeer::GetActiveSession(factory_.get(), + host_port_pair); + } + std::unique_ptr<QuicHttpStream> CreateFromSession( const HostPortPair& host_port_pair) { - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair); return QuicStreamFactoryPeer::CreateFromSession(factory_.get(), session); } @@ -317,8 +322,7 @@ EXPECT_TRUE(stream.get()); stream.reset(); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), destination); + QuicChromiumClientSession* session = GetActiveSession(destination); if (socket_count + 1 != socket_factory_.udp_client_socket_ports().size()) { ADD_FAILURE(); @@ -592,13 +596,11 @@ std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); EXPECT_TRUE(stream.get()); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); session->OnGoAway(QuicGoAwayFrame()); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); + EXPECT_FALSE(HasActiveSession(host_port_pair_)); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed()); @@ -623,8 +625,7 @@ std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); EXPECT_TRUE(stream.get()); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); session->OnGoAway( QuicGoAwayFrame(QUIC_ERROR_MIGRATING_PORT, 0, @@ -637,8 +638,7 @@ stream->PopulateNetErrorDetails(&details); EXPECT_TRUE(details.quic_port_migration_detected); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); + EXPECT_FALSE(HasActiveSession(host_port_pair_)); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed()); @@ -674,9 +674,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_EQ( - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2)); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed()); @@ -716,9 +714,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_NE( - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_NE(GetActiveSession(host_port_pair_), GetActiveSession(server2)); EXPECT_TRUE(socket_data1.AllReadDataConsumed()); EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); @@ -759,12 +755,9 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - factory_->OnSessionGoingAway( - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_)); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server2)); + factory_->OnSessionGoingAway(GetActiveSession(host_port_pair_)); + EXPECT_FALSE(HasActiveSession(host_port_pair_)); + EXPECT_FALSE(HasActiveSession(server2)); TestCompletionCallback callback3; QuicStreamRequest request3(factory_.get()); @@ -774,7 +767,7 @@ std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream(); EXPECT_TRUE(stream3.get()); - EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server2)); + EXPECT_TRUE(HasActiveSession(server2)); EXPECT_TRUE(socket_data1.AllReadDataConsumed()); EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); @@ -814,8 +807,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_EQ(QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server1), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2)); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed()); @@ -857,8 +849,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server1), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2)); EXPECT_TRUE(socket_data1.AllReadDataConsumed()); EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); @@ -974,8 +965,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_EQ(QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server1), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2)); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed()); @@ -1023,8 +1013,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server1), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2)); EXPECT_TRUE(socket_data1.AllReadDataConsumed()); EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); @@ -1077,8 +1066,7 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server1), - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2)); + EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2)); EXPECT_TRUE(socket_data1.AllReadDataConsumed()); EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); @@ -1110,13 +1098,11 @@ // Mark the session as going away. Ensure that while it is still alive // that it is no longer active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); factory_->OnSessionGoingAway(session); EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); + EXPECT_FALSE(HasActiveSession(host_port_pair_)); EXPECT_FALSE(HasActiveSession(host_port_pair_)); // Create a new request for the same destination and verify that a @@ -1130,10 +1116,8 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_TRUE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); - EXPECT_NE(session, QuicStreamFactoryPeer::GetActiveSession(factory_.get(), - host_port_pair_)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_NE(session, GetActiveSession(host_port_pair_)); EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -1210,8 +1194,7 @@ // Force close of the connection to suppress the generation of RST // packets when streams are torn down, which wouldn't be relevant to // this test anyway. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -1460,8 +1443,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1517,10 +1499,8 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_TRUE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); - QuicChromiumClientSession* new_session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_); EXPECT_NE(session, new_session); // On a DISCONNECTED notification, nothing happens to the migrated @@ -1575,8 +1555,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1628,10 +1607,8 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_TRUE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); - EXPECT_NE(session, QuicStreamFactoryPeer::GetActiveSession(factory_.get(), - host_port_pair_)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_NE(session, GetActiveSession(host_port_pair_)); EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -1675,8 +1652,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(1u, session->GetNumActiveStreams()); @@ -1729,8 +1705,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1778,8 +1753,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1830,8 +1804,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1882,8 +1855,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1935,8 +1907,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -1992,8 +1963,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2043,8 +2013,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2086,8 +2055,7 @@ EXPECT_TRUE(stream.get()); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2124,8 +2092,7 @@ EXPECT_TRUE(stream.get()); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2175,8 +2142,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2235,10 +2201,8 @@ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); - EXPECT_TRUE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); - QuicChromiumClientSession* new_session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_); EXPECT_NE(session, new_session); // On a SOON_TO_DISCONNECT notification, nothing happens to the @@ -2296,8 +2260,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2353,8 +2316,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2408,8 +2370,7 @@ net_log_, CompletionCallback())); // Ensure that session is alive and active. - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); @@ -2809,8 +2770,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); DVLOG(1) << "Create 1st session and test packet loss"; @@ -2818,8 +2778,7 @@ EXPECT_FALSE( factory_->OnHandshakeConfirmed(session, /*packet_loss_rate=*/0.9f)); EXPECT_TRUE(session->connection()->connected()); - EXPECT_TRUE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), host_port_pair_.port())); EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections( @@ -2834,8 +2793,7 @@ EXPECT_TRUE(session->connection()->connected()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), host_port_pair_.port())); - EXPECT_TRUE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); // Test N-in-a-row high packet loss connections. @@ -2846,8 +2804,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); // If there is no packet loss during handshake confirmation, number of lossy // connections for the port should be 0. @@ -2869,7 +2826,7 @@ EXPECT_TRUE(session2->connection()->connected()); EXPECT_FALSE( QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server2.port())); - EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server2)); + EXPECT_TRUE(HasActiveSession(server2)); DVLOG(1) << "Create 3rd session which also has packet loss"; @@ -2878,8 +2835,7 @@ EXPECT_EQ(OK, request3.Request(server3, privacy_mode_, /*cert_verify_flags=*/0, url3_, "GET", net_log_, callback3.callback())); - QuicChromiumClientSession* session3 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server3); + QuicChromiumClientSession* session3 = GetActiveSession(server3); DVLOG(1) << "Create 4th session with packet loss and test IsQuicDisabled()"; TestCompletionCallback callback4; @@ -2887,8 +2843,7 @@ EXPECT_EQ(OK, request4.Request(server4, privacy_mode_, /*cert_verify_flags=*/0, url4_, "GET", net_log_, callback4.callback())); - QuicChromiumClientSession* session4 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server4); + QuicChromiumClientSession* session4 = GetActiveSession(server4); // Set packet_loss_rate to higher value than packet_loss_threshold 2nd time in // a row and that should close the session and disable QUIC. @@ -2899,8 +2854,7 @@ EXPECT_FALSE(session3->connection()->connected()); EXPECT_TRUE( QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server3.port())); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server3)); + EXPECT_FALSE(HasActiveSession(server3)); EXPECT_FALSE(HasActiveSession(server3)); // Set packet_loss_rate to higher value than packet_loss_threshold 3rd time in @@ -2912,8 +2866,7 @@ EXPECT_FALSE(session4->connection()->connected()); EXPECT_TRUE( QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server4.port())); - EXPECT_FALSE( - QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server4)); + EXPECT_FALSE(HasActiveSession(server4)); EXPECT_FALSE(HasActiveSession(server4)); std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); @@ -2969,8 +2922,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); DVLOG(1) << "Created 1st session. Now trigger public reset post handshake"; session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test", @@ -2992,8 +2944,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); session2->connection()->CloseConnection( QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3054,8 +3005,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); EXPECT_TRUE(stream.get()); @@ -3084,8 +3034,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); EXPECT_TRUE(stream2.get()); @@ -3159,8 +3108,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); DVLOG(1) << "Created 1st session. Now trigger public reset post handshake"; session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test", @@ -3181,8 +3129,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); session2->connection()->CloseConnection( QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3202,8 +3149,7 @@ EXPECT_EQ(OK, request3.Request(server3, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback3.callback())); - QuicChromiumClientSession* session3 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server3); + QuicChromiumClientSession* session3 = GetActiveSession(server3); session3->connection()->CloseConnection( QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3277,8 +3223,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); EXPECT_TRUE(stream.get()); @@ -3307,8 +3252,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); session2->connection()->CloseConnection( QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3329,8 +3273,7 @@ EXPECT_EQ(OK, request3.Request(server3, privacy_mode_, /*cert_verify_flags=*/0, url3_, "GET", net_log_, callback3.callback())); - QuicChromiumClientSession* session3 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server3); + QuicChromiumClientSession* session3 = GetActiveSession(server3); std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream(); EXPECT_TRUE(stream3.get()); @@ -3396,8 +3339,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); EXPECT_TRUE(stream.get()); @@ -3485,8 +3427,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); DVLOG(1) << "Created 1st session. Now trigger public reset post handshake"; session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test", @@ -3507,8 +3448,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); session2->connection()->CloseConnection( QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3526,8 +3466,7 @@ EXPECT_EQ(OK, request3.Request(server3, privacy_mode_, /*cert_verify_flags=*/0, url3_, "GET", net_log_, callback3.callback())); - QuicChromiumClientSession* session3 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server3); + QuicChromiumClientSession* session3 = GetActiveSession(server3); session3->connection()->CloseConnection( QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3547,8 +3486,7 @@ EXPECT_EQ(OK, request4.Request(server4, privacy_mode_, /*cert_verify_flags=*/0, url4_, "GET", net_log_, callback4.callback())); - QuicChromiumClientSession* session4 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server4); + QuicChromiumClientSession* session4 = GetActiveSession(server4); session4->connection()->CloseConnection( QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3629,8 +3567,7 @@ /*cert_verify_flags=*/0, url_, "GET", net_log_, callback_.callback())); - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); EXPECT_TRUE(stream.get()); @@ -3658,8 +3595,7 @@ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_, /*cert_verify_flags=*/0, url2_, "GET", net_log_, callback2.callback())); - QuicChromiumClientSession* session2 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server2); + QuicChromiumClientSession* session2 = GetActiveSession(server2); session2->connection()->CloseConnection( QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3677,8 +3613,7 @@ EXPECT_EQ(OK, request3.Request(server3, privacy_mode_, /*cert_verify_flags=*/0, url3_, "GET", net_log_, callback3.callback())); - QuicChromiumClientSession* session3 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server3); + QuicChromiumClientSession* session3 = GetActiveSession(server3); session3->connection()->CloseConnection( QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE); @@ -3699,8 +3634,7 @@ EXPECT_EQ(OK, request4.Request(server4, privacy_mode_, /*cert_verify_flags=*/0, url4_, "GET", net_log_, callback4.callback())); - QuicChromiumClientSession* session4 = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server4); + QuicChromiumClientSession* session4 = GetActiveSession(server4); std::unique_ptr<QuicHttpStream> stream4 = request4.CreateStream(); EXPECT_TRUE(stream4.get()); @@ -4080,8 +4014,7 @@ std::string url = "https://www.example.org/"; - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); QuicClientPromisedInfo promised(session, kServerDataStreamId1, url); (*QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get()) @@ -4129,8 +4062,7 @@ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get())); std::string url = "https://www.example.org/"; - QuicChromiumClientSession* session = - QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_); + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); QuicClientPromisedInfo promised(session, kServerDataStreamId1, url);
diff --git a/net/quic/test_tools/crypto_test_utils_chromium.cc b/net/quic/test_tools/crypto_test_utils_chromium.cc index d78df969..121db431 100644 --- a/net/quic/test_tools/crypto_test_utils_chromium.cc +++ b/net/quic/test_tools/crypto_test_utils_chromium.cc
@@ -75,157 +75,11 @@ std::unique_ptr<CTVerifier> cert_transparency_verifier_; }; -const char kSignature[] = "signature"; -const char kSCT[] = "CryptoServerTests"; - -class FakeProofSource : public ProofSource { - public: - FakeProofSource() {} - ~FakeProofSource() override {} - - // ProofSource interface - bool Initialize(const base::FilePath& cert_path, - const base::FilePath& key_path, - const base::FilePath& sct_path) { - std::string cert_data; - if (!base::ReadFileToString(cert_path, &cert_data)) { - DLOG(FATAL) << "Unable to read certificates."; - return false; - } - - CertificateList certs_in_file = - X509Certificate::CreateCertificateListFromBytes( - cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO); - - if (certs_in_file.empty()) { - DLOG(FATAL) << "No certificates."; - return false; - } - - vector<string> certs; - for (const scoped_refptr<X509Certificate>& cert : certs_in_file) { - std::string der_encoded_cert; - if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), - &der_encoded_cert)) { - return false; - } - certs.push_back(der_encoded_cert); - } - chain_ = new ProofSource::Chain(certs); - return true; - } - - bool GetProof(const IPAddress& server_ip, - const std::string& hostname, - const std::string& server_config, - QuicVersion quic_version, - StringPiece chlo_hash, - bool ecdsa_ok, - scoped_refptr<ProofSource::Chain>* out_chain, - std::string* out_signature, - std::string* out_leaf_cert_sct) override { - out_signature->assign(kSignature); - *out_chain = chain_; - *out_leaf_cert_sct = kSCT; - return true; - } - - private: - scoped_refptr<ProofSource::Chain> chain_; - - DISALLOW_COPY_AND_ASSIGN(FakeProofSource); -}; - -class FakeProofVerifier : public TestProofVerifierChromium { - public: - FakeProofVerifier( - std::unique_ptr<CertVerifier> cert_verifier, - std::unique_ptr<TransportSecurityState> transport_security_state, - std::unique_ptr<CTVerifier> cert_transparency_verifier, - const std::string& cert_file) - : TestProofVerifierChromium(std::move(cert_verifier), - std::move(transport_security_state), - std::move(cert_transparency_verifier), - cert_file) {} - ~FakeProofVerifier() override {} - - // ProofVerifier interface - QuicAsyncStatus VerifyProof( - const std::string& hostname, - const uint16_t port, - const std::string& server_config, - QuicVersion quic_version, - StringPiece chlo_hash, - const std::vector<std::string>& certs, - const std::string& cert_sct, - const std::string& signature, - const ProofVerifyContext* verify_context, - std::string* error_details, - std::unique_ptr<ProofVerifyDetails>* verify_details, - ProofVerifierCallback* callback) override { - error_details->clear(); - std::unique_ptr<ProofVerifyDetailsChromium> verify_details_chromium( - new ProofVerifyDetailsChromium); - DCHECK(!certs.empty()); - // Convert certs to X509Certificate. - vector<StringPiece> cert_pieces(certs.size()); - for (unsigned i = 0; i < certs.size(); i++) { - cert_pieces[i] = base::StringPiece(certs[i]); - } - scoped_refptr<X509Certificate> x509_cert = - X509Certificate::CreateFromDERCertChain(cert_pieces); - - if (!x509_cert.get()) { - *error_details = "Failed to create certificate chain"; - verify_details_chromium->cert_verify_result.cert_status = - CERT_STATUS_INVALID; - *verify_details = std::move(verify_details_chromium); - return QUIC_FAILURE; - } - - const ProofVerifyContextChromium* chromium_context = - reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); - std::unique_ptr<CertVerifier::Request> cert_verifier_request_; - TestCompletionCallback test_callback; - int result = cert_verifier()->Verify( - x509_cert.get(), hostname, std::string(), - chromium_context->cert_verify_flags, - SSLConfigService::GetCRLSet().get(), - &verify_details_chromium->cert_verify_result, test_callback.callback(), - &cert_verifier_request_, chromium_context->net_log); - if (result != OK) { - std::string error_string = ErrorToString(result); - *error_details = StringPrintf("Failed to verify certificate chain: %s", - error_string.c_str()); - verify_details_chromium->cert_verify_result.cert_status = - CERT_STATUS_INVALID; - *verify_details = std::move(verify_details_chromium); - return QUIC_FAILURE; - } - if (signature != kSignature) { - *error_details = "Invalid proof"; - verify_details_chromium->cert_verify_result.cert_status = - CERT_STATUS_INVALID; - *verify_details = std::move(verify_details_chromium); - return QUIC_FAILURE; - } - *verify_details = std::move(verify_details_chromium); - return QUIC_SUCCESS; - } - - private: - DISALLOW_COPY_AND_ASSIGN(FakeProofVerifier); -}; - } // namespace // static ProofSource* CryptoTestUtils::ProofSourceForTesting() { -#if defined(USE_OPENSSL) ProofSourceChromium* source = new ProofSourceChromium(); -#else - FakeProofSource* source = new FakeProofSource(); -#endif base::FilePath certs_dir = GetTestCertsDirectory(); CHECK(source->Initialize( certs_dir.AppendASCII("quic_chain.crt"), @@ -252,15 +106,9 @@ std::move(cert_verifier), base::WrapUnique(new TransportSecurityState), base::WrapUnique(new MultiLogCTVerifier), "quic_root.crt"); } -#if defined(USE_OPENSSL) return new TestProofVerifierChromium( std::move(cert_verifier), base::WrapUnique(new TransportSecurityState), base::WrapUnique(new MultiLogCTVerifier), "quic_root.crt"); -#else - return new FakeProofVerifier( - std::move(cert_verifier), base::WrapUnique(new TransportSecurityState), - base::WrapUnique(new MultiLogCTVerifier), "quic_root.crt"); -#endif } // static
diff --git a/net/quic/test_tools/crypto_test_utils_nss.cc b/net/quic/test_tools/crypto_test_utils_nss.cc deleted file mode 100644 index c34dc01..0000000 --- a/net/quic/test_tools/crypto_test_utils_nss.cc +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2013 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/memory/ptr_util.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "crypto/ec_private_key.h" -#include "crypto/ec_signature_creator.h" -#include "net/quic/crypto/channel_id.h" -#include "net/quic/crypto/channel_id_chromium.h" -#include "net/quic/test_tools/crypto_test_utils.h" - -using base::StringPiece; -using std::string; - -namespace net { - -namespace test { - -class TestChannelIDSource : public ChannelIDSource { - public: - ~TestChannelIDSource() override { STLDeleteValues(&hostname_to_key_); } - - // ChannelIDSource implementation. - - QuicAsyncStatus GetChannelIDKey( - const string& hostname, - std::unique_ptr<ChannelIDKey>* channel_id_key, - ChannelIDSourceCallback* /*callback*/) override { - channel_id_key->reset(new ChannelIDKeyChromium(HostnameToKey(hostname))); - return QUIC_SUCCESS; - } - - private: - typedef std::map<string, crypto::ECPrivateKey*> HostnameToKeyMap; - - std::unique_ptr<crypto::ECPrivateKey> HostnameToKey(const string& hostname) { - HostnameToKeyMap::const_iterator it = hostname_to_key_.find(hostname); - if (it != hostname_to_key_.end()) { - return base::WrapUnique(it->second->Copy()); - } - - crypto::ECPrivateKey* keypair = crypto::ECPrivateKey::Create(); - if (!keypair) { - return nullptr; - } - hostname_to_key_[hostname] = keypair; - return base::WrapUnique(keypair->Copy()); - } - - HostnameToKeyMap hostname_to_key_; -}; - -// static -ChannelIDSource* CryptoTestUtils::ChannelIDSourceForTesting() { - return new TestChannelIDSource(); -} - -} // namespace test - -} // namespace net
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc index 99f5712..9ddd05d6 100644 --- a/net/quic/test_tools/quic_test_packet_maker.cc +++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -139,7 +139,7 @@ QuicPacketNumber largest_received, QuicPacketNumber least_unacked, QuicErrorCode quic_error, - std::string& quic_error_details) { + const std::string& quic_error_details) { QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.reset_flag = false;
diff --git a/net/quic/test_tools/quic_test_packet_maker.h b/net/quic/test_tools/quic_test_packet_maker.h index e60ab3c..dec0c677 100644 --- a/net/quic/test_tools/quic_test_packet_maker.h +++ b/net/quic/test_tools/quic_test_packet_maker.h
@@ -62,7 +62,7 @@ QuicPacketNumber largest_received, QuicPacketNumber least_unacked, QuicErrorCode quic_error, - std::string& quic_error_details); + const std::string& quic_error_details); std::unique_ptr<QuicReceivedPacket> MakeConnectionClosePacket( QuicPacketNumber num); std::unique_ptr<QuicReceivedPacket> MakeGoAwayPacket(
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc index 78685594..c7597c5 100644 --- a/net/socket/client_socket_factory.cc +++ b/net/socket/client_socket_factory.cc
@@ -10,15 +10,10 @@ #include "build/build_config.h" #include "net/cert/cert_database.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/ssl_client_socket_openssl.h" #include "net/socket/tcp_client_socket.h" #include "net/udp/udp_client_socket.h" -#if defined(USE_OPENSSL) -#include "net/socket/ssl_client_socket_openssl.h" -#else -#include "net/socket/ssl_client_socket_nss.h" -#endif - namespace net { class X509Certificate; @@ -72,13 +67,8 @@ const HostPortPair& host_and_port, const SSLConfig& ssl_config, const SSLClientSocketContext& context) override { -#if defined(USE_OPENSSL) return std::unique_ptr<SSLClientSocket>(new SSLClientSocketOpenSSL( std::move(transport_socket), host_and_port, ssl_config, context)); -#else - return std::unique_ptr<SSLClientSocket>(new SSLClientSocketNSS( - std::move(transport_socket), host_and_port, ssl_config, context)); -#endif } void ClearSSLSessionCache() override { SSLClientSocket::ClearSessionCache(); }
diff --git a/net/socket/nss_ssl_util.cc b/net/socket/nss_ssl_util.cc deleted file mode 100644 index 274aa2da..0000000 --- a/net/socket/nss_ssl_util.cc +++ /dev/null
@@ -1,412 +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. - -#include "net/socket/nss_ssl_util.h" - -#include <nss.h> -#include <secerr.h> -#include <ssl.h> -#include <sslerr.h> -#include <sslproto.h> - -#include <string> -#include <utility> - -#include "base/bind.h" -#include "base/cpu.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/threading/thread_restrictions.h" -#include "base/values.h" -#include "build/build_config.h" -#include "crypto/nss_util.h" -#include "net/base/net_errors.h" -#include "net/base/nss_memio.h" -#include "net/log/net_log.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#endif - -namespace net { - -namespace { - -// CiphersRemove takes a zero-terminated array of cipher suite ids in -// |to_remove| and sets every instance of them in |ciphers| to zero. It returns -// true if it found and removed every element of |to_remove|. It assumes that -// there are no duplicates in |ciphers| nor in |to_remove|. -bool CiphersRemove(const uint16_t* to_remove, uint16_t* ciphers, size_t num) { - size_t i, found = 0; - - for (i = 0; ; i++) { - if (to_remove[i] == 0) - break; - - for (size_t j = 0; j < num; j++) { - if (to_remove[i] == ciphers[j]) { - ciphers[j] = 0; - found++; - break; - } - } - } - - return found == i; -} - -// CiphersCompact takes an array of cipher suite ids in |ciphers|, where some -// entries are zero, and moves the entries so that all the non-zero elements -// are compacted at the end of the array. -void CiphersCompact(uint16_t* ciphers, size_t num) { - size_t j = num - 1; - - for (size_t i = num - 1; i < num; i--) { - if (ciphers[i] == 0) - continue; - ciphers[j--] = ciphers[i]; - } -} - -// CiphersCopy copies the zero-terminated array |in| to |out|. It returns the -// number of cipher suite ids copied. -size_t CiphersCopy(const uint16_t* in, uint16_t* out) { - for (size_t i = 0; ; i++) { - if (in[i] == 0) - return i; - out[i] = in[i]; - } -} - -std::unique_ptr<base::Value> NetLogSSLErrorCallback( - int net_error, - int ssl_lib_error, - NetLogCaptureMode /* capture_mode */) { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetInteger("net_error", net_error); - if (ssl_lib_error) - dict->SetInteger("ssl_lib_error", ssl_lib_error); - return std::move(dict); -} - -class NSSSSLInitSingleton { - public: - NSSSSLInitSingleton() : model_fd_(NULL) { - crypto::EnsureNSSInit(); - - NSS_SetDomesticPolicy(); - - const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers(); - const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers(); - - // Disable ECDSA cipher suites on platforms that do not support ECDSA - // signed certificates, as servers may use the presence of such - // ciphersuites as a hint to send an ECDSA certificate. - bool disableECDSA = false; -#if defined(OS_WIN) - if (base::win::GetVersion() < base::win::VERSION_VISTA) - disableECDSA = true; -#endif - - // Explicitly enable exactly those ciphers with keys of at least 80 bits. - for (int i = 0; i < num_ciphers; i++) { - SSLCipherSuiteInfo info; - if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, - sizeof(info)) == SECSuccess) { - bool enabled = info.effectiveKeyBits >= 80; - if (info.authAlgorithm == ssl_auth_ecdsa && disableECDSA) - enabled = false; - - // Trim the list of cipher suites in order to keep the size of the - // ClientHello down. DSS, ECDH, CAMELLIA, SEED, ECC+3DES, and - // HMAC-SHA256 cipher suites are disabled. - if (info.symCipher == ssl_calg_camellia || - info.symCipher == ssl_calg_seed || - (info.symCipher == ssl_calg_3des && info.keaType != ssl_kea_rsa) || - info.authAlgorithm == ssl_auth_dsa || - info.macAlgorithm == ssl_hmac_sha256 || - info.nonStandard || - strcmp(info.keaTypeName, "ECDH") == 0) { - enabled = false; - } - - SSL_CipherPrefSetDefault(ssl_ciphers[i], enabled); - } - } - - // Enable SSL. - SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); - - // Calculate the order of ciphers that we'll use for NSS sockets. (Note - // that, even if a cipher is specified in the ordering, it must still be - // enabled in order to be included in a ClientHello.) - // - // Our top preference cipher suites are either forward-secret AES-GCM or - // forward-secret ChaCha20-Poly1305. If the local machine has AES-NI then - // we prefer AES-GCM, otherwise ChaCha20. The remainder of the cipher suite - // preference is inheriented from NSS. */ - static const uint16_t chacha_ciphers[] = { - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0, - }; - static const uint16_t aes_gcm_ciphers[] = { - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 0, - }; - std::unique_ptr<uint16_t[]> ciphers(new uint16_t[num_ciphers]); - memcpy(ciphers.get(), ssl_ciphers, sizeof(uint16_t) * num_ciphers); - - if (CiphersRemove(chacha_ciphers, ciphers.get(), num_ciphers) && - CiphersRemove(aes_gcm_ciphers, ciphers.get(), num_ciphers)) { - CiphersCompact(ciphers.get(), num_ciphers); - - const uint16_t* preference_ciphers = chacha_ciphers; - const uint16_t* other_ciphers = aes_gcm_ciphers; - base::CPU cpu; - - if (cpu.has_aesni() && cpu.has_avx()) { - preference_ciphers = aes_gcm_ciphers; - other_ciphers = chacha_ciphers; - } - unsigned i = CiphersCopy(preference_ciphers, ciphers.get()); - CiphersCopy(other_ciphers, &ciphers[i]); - - if ((model_fd_ = memio_CreateIOLayer(1, 1)) == NULL || - SSL_ImportFD(NULL, model_fd_) == NULL || - SECSuccess != - SSL_CipherOrderSet(model_fd_, ciphers.get(), num_ciphers)) { - NOTREACHED(); - if (model_fd_) { - PR_Close(model_fd_); - model_fd_ = NULL; - } - } - } - - // All other SSL options are set per-session by SSLClientSocket and - // SSLServerSocket. - } - - PRFileDesc* GetModelSocket() { - return model_fd_; - } - - ~NSSSSLInitSingleton() { - // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY. - SSL_ClearSessionCache(); - if (model_fd_) - PR_Close(model_fd_); - } - - private: - PRFileDesc* model_fd_; -}; - -base::LazyInstance<NSSSSLInitSingleton>::Leaky g_nss_ssl_init_singleton = - LAZY_INSTANCE_INITIALIZER; - -} // anonymous namespace - -// Initialize the NSS SSL library if it isn't already initialized. This must -// be called before any other NSS SSL functions. This function is -// thread-safe, and the NSS SSL library will only ever be initialized once. -// The NSS SSL library will be properly shut down on program exit. -void EnsureNSSSSLInit() { - // Initializing SSL causes us to do blocking IO. - // Temporarily allow it until we fix - // http://code.google.com/p/chromium/issues/detail?id=59847 - base::ThreadRestrictions::ScopedAllowIO allow_io; - - g_nss_ssl_init_singleton.Get(); -} - -PRFileDesc* GetNSSModelSocket() { - return g_nss_ssl_init_singleton.Get().GetModelSocket(); -} - -// Map a Chromium net error code to an NSS error code. -// See _MD_unix_map_default_error in the NSS source -// tree for inspiration. -PRErrorCode MapErrorToNSS(int result) { - if (result >=0) - return result; - - switch (result) { - case ERR_IO_PENDING: - return PR_WOULD_BLOCK_ERROR; - case ERR_ACCESS_DENIED: - case ERR_NETWORK_ACCESS_DENIED: - // For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR. - return PR_NO_ACCESS_RIGHTS_ERROR; - case ERR_NOT_IMPLEMENTED: - return PR_NOT_IMPLEMENTED_ERROR; - case ERR_SOCKET_NOT_CONNECTED: - return PR_NOT_CONNECTED_ERROR; - case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN. - return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation. - case ERR_CONNECTION_TIMED_OUT: - case ERR_TIMED_OUT: - return PR_IO_TIMEOUT_ERROR; - case ERR_CONNECTION_RESET: - return PR_CONNECT_RESET_ERROR; - case ERR_CONNECTION_ABORTED: - return PR_CONNECT_ABORTED_ERROR; - case ERR_CONNECTION_REFUSED: - return PR_CONNECT_REFUSED_ERROR; - case ERR_ADDRESS_UNREACHABLE: - return PR_HOST_UNREACHABLE_ERROR; // Also PR_NETWORK_UNREACHABLE_ERROR. - case ERR_ADDRESS_INVALID: - return PR_ADDRESS_NOT_AVAILABLE_ERROR; - case ERR_NAME_NOT_RESOLVED: - return PR_DIRECTORY_LOOKUP_ERROR; - default: - LOG(WARNING) << "MapErrorToNSS " << result - << " mapped to PR_UNKNOWN_ERROR"; - return PR_UNKNOWN_ERROR; - } -} - -// The default error mapping function. -// Maps an NSS error code to a network error code. -int MapNSSError(PRErrorCode err) { - // TODO(port): fill this out as we learn what's important - switch (err) { - case PR_WOULD_BLOCK_ERROR: - return ERR_IO_PENDING; - case PR_ADDRESS_NOT_SUPPORTED_ERROR: // For connect. - case PR_NO_ACCESS_RIGHTS_ERROR: - return ERR_ACCESS_DENIED; - case PR_IO_TIMEOUT_ERROR: - return ERR_TIMED_OUT; - case PR_CONNECT_RESET_ERROR: - return ERR_CONNECTION_RESET; - case PR_CONNECT_ABORTED_ERROR: - return ERR_CONNECTION_ABORTED; - case PR_CONNECT_REFUSED_ERROR: - return ERR_CONNECTION_REFUSED; - case PR_NOT_CONNECTED_ERROR: - return ERR_SOCKET_NOT_CONNECTED; - case PR_HOST_UNREACHABLE_ERROR: - case PR_NETWORK_UNREACHABLE_ERROR: - return ERR_ADDRESS_UNREACHABLE; - case PR_ADDRESS_NOT_AVAILABLE_ERROR: - return ERR_ADDRESS_INVALID; - case PR_INVALID_ARGUMENT_ERROR: - return ERR_INVALID_ARGUMENT; - case PR_END_OF_FILE_ERROR: - return ERR_CONNECTION_CLOSED; - case PR_NOT_IMPLEMENTED_ERROR: - return ERR_NOT_IMPLEMENTED; - - case SEC_ERROR_LIBRARY_FAILURE: - return ERR_UNEXPECTED; - case SEC_ERROR_INVALID_ARGS: - return ERR_INVALID_ARGUMENT; - case SEC_ERROR_NO_MEMORY: - return ERR_OUT_OF_MEMORY; - case SEC_ERROR_NO_KEY: - return ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY; - case SEC_ERROR_INVALID_KEY: - case SSL_ERROR_SIGN_HASHES_FAILURE: - LOG(ERROR) << "ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED: NSS error " << err - << ", OS error " << PR_GetOSError(); - return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; - // A handshake (initial or renegotiation) may fail because some signature - // (for example, the signature in the ServerKeyExchange message for an - // ephemeral Diffie-Hellman cipher suite) is invalid. - case SEC_ERROR_BAD_SIGNATURE: - return ERR_SSL_PROTOCOL_ERROR; - - case SSL_ERROR_SSL_DISABLED: - return ERR_NO_SSL_VERSIONS_ENABLED; - case SSL_ERROR_NO_CYPHER_OVERLAP: - case SSL_ERROR_PROTOCOL_VERSION_ALERT: - case SSL_ERROR_UNSUPPORTED_VERSION: - return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; - case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: - case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: - case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: - return ERR_SSL_PROTOCOL_ERROR; - case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT: - return ERR_SSL_DECOMPRESSION_FAILURE_ALERT; - case SSL_ERROR_BAD_MAC_ALERT: - return ERR_SSL_BAD_RECORD_MAC_ALERT; - case SSL_ERROR_DECRYPT_ERROR_ALERT: - return ERR_SSL_DECRYPT_ERROR_ALERT; - case SSL_ERROR_UNRECOGNIZED_NAME_ALERT: - return ERR_SSL_UNRECOGNIZED_NAME_ALERT; - case SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY: - return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY; - case SSL_ERROR_HANDSHAKE_NOT_COMPLETED: - return ERR_SSL_HANDSHAKE_NOT_COMPLETED; - case SEC_ERROR_BAD_KEY: - case SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE: - // TODO(wtc): the following errors may also occur in contexts unrelated - // to the peer's public key. We should add new error codes for them, or - // map them to ERR_SSL_BAD_PEER_PUBLIC_KEY only in the right context. - // General unsupported/unknown key algorithm error. - case SEC_ERROR_UNSUPPORTED_KEYALG: - // General DER decoding errors. - case SEC_ERROR_BAD_DER: - case SEC_ERROR_EXTRA_INPUT: - return ERR_SSL_BAD_PEER_PUBLIC_KEY; - // During renegotiation, the server presented a different certificate than - // was used earlier. - case SSL_ERROR_WRONG_CERTIFICATE: - return ERR_SSL_SERVER_CERT_CHANGED; - case SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT: - return ERR_SSL_INAPPROPRIATE_FALLBACK; - - default: { - const char* err_name = PR_ErrorToName(err); - if (err_name == NULL) - err_name = ""; - if (IS_SSL_ERROR(err)) { - LOG(WARNING) << "Unknown SSL error " << err << " (" << err_name << ")" - << " mapped to net::ERR_SSL_PROTOCOL_ERROR"; - return ERR_SSL_PROTOCOL_ERROR; - } - LOG(WARNING) << "Unknown error " << err << " (" << err_name << ")" - << " mapped to net::ERR_FAILED"; - return ERR_FAILED; - } - } -} - -// Returns parameters to attach to the NetLog when we receive an error in -// response to a call to an NSS function. Used instead of -// NetLogSSLErrorCallback with events of type TYPE_SSL_NSS_ERROR. -std::unique_ptr<base::Value> NetLogSSLFailedNSSFunctionCallback( - const char* function, - const char* param, - int ssl_lib_error, - NetLogCaptureMode /* capture_mode */) { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("function", function); - if (param[0] != '\0') - dict->SetString("param", param); - dict->SetInteger("ssl_lib_error", ssl_lib_error); - return std::move(dict); -} - -void LogFailedNSSFunction(const BoundNetLog& net_log, - const char* function, - const char* param) { - DCHECK(function); - DCHECK(param); - net_log.AddEvent( - NetLog::TYPE_SSL_NSS_ERROR, - base::Bind(&NetLogSSLFailedNSSFunctionCallback, - function, param, PR_GetError())); -} - -NetLog::ParametersCallback CreateNetLogSSLErrorCallback(int net_error, - int ssl_lib_error) { - return base::Bind(&NetLogSSLErrorCallback, net_error, ssl_lib_error); -} - -} // namespace net
diff --git a/net/socket/nss_ssl_util.h b/net/socket/nss_ssl_util.h deleted file mode 100644 index 5d9ec7e..0000000 --- a/net/socket/nss_ssl_util.h +++ /dev/null
@@ -1,46 +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. - -// This file is only included in ssl_client_socket_nss.cc and -// ssl_server_socket_nss.cc to share common functions of NSS. - -#ifndef NET_SOCKET_NSS_SSL_UTIL_H_ -#define NET_SOCKET_NSS_SSL_UTIL_H_ - -#include <prerror.h> -#include <prio.h> - -#include "net/base/net_export.h" -#include "net/log/net_log.h" - -namespace net { - -class BoundNetLog; - -// Initalize NSS SSL library. -NET_EXPORT void EnsureNSSSSLInit(); - -// Log a failed NSS funcion call. -void LogFailedNSSFunction(const BoundNetLog& net_log, - const char* function, - const char* param); - -// Map network error code to NSS error code. -PRErrorCode MapErrorToNSS(int result); - -// GetNSSModelSocket returns either NULL, or an NSS socket that can be passed -// to |SSL_ImportFD| in order to inherit some default options. -PRFileDesc* GetNSSModelSocket(); - -// Map NSS error code to network error code. -int MapNSSError(PRErrorCode err); - -// Creates a NetLog callback for an SSL error. -NetLog::ParametersCallback CreateNetLogSSLErrorCallback(int net_error, - int ssl_lib_error); - - -} // namespace net - -#endif // NET_SOCKET_NSS_SSL_UTIL_H_
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc index a7c0dd4..b076fb4 100644 --- a/net/socket/ssl_client_socket.cc +++ b/net/socket/ssl_client_socket.cc
@@ -10,14 +10,12 @@ #include "crypto/ec_private_key.h" #include "net/base/connection_type_histograms.h" #include "net/base/net_errors.h" +#include "net/socket/ssl_client_socket_openssl.h" #include "net/ssl/channel_id_service.h" #include "net/ssl/ssl_cipher_suite_names.h" #include "net/ssl/ssl_config_service.h" #include "net/ssl/ssl_connection_status_flags.h" -#if defined(USE_OPENSSL) -#include "net/socket/ssl_client_socket_openssl.h" -#endif namespace net { @@ -78,7 +76,7 @@ void SSLClientSocket::SetSSLKeyLogFile( const base::FilePath& path, const scoped_refptr<base::SequencedTaskRunner>& task_runner) { -#if defined(USE_OPENSSL) && !defined(OS_NACL) +#if !defined(OS_NACL) SSLClientSocketOpenSSL::SetSSLKeyLogFile(path, task_runner); #else NOTIMPLEMENTED();
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc deleted file mode 100644 index 1d5c7157..0000000 --- a/net/socket/ssl_client_socket_nss.cc +++ /dev/null
@@ -1,3189 +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. - -// This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived -// from AuthCertificateCallback() in -// mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. - -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Ian McGreer <mcgreer@netscape.com> - * Javier Delgadillo <javi@netscape.com> - * Kai Engert <kengert@redhat.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "net/socket/ssl_client_socket_nss.h" - -#include <certdb.h> -#include <hasht.h> -#include <keyhi.h> -#include <nspr.h> -#include <nss.h> -#include <ocsp.h> -#include <pk11pub.h> -#include <secerr.h> -#include <sechash.h> -#include <ssl.h> -#include <sslerr.h> -#include <sslproto.h> - -#include <algorithm> -#include <limits> -#include <map> -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_helpers.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/metrics/histogram_macros.h" -#include "base/single_thread_task_runner.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/thread_task_runner_handle.h" -#include "base/threading/thread_restrictions.h" -#include "base/values.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 "net/base/address_list.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/base/sockaddr_storage.h" -#include "net/cert/asn1_util.h" -#include "net/cert/cert_status_flags.h" -#include "net/cert/cert_verifier.h" -#include "net/cert/ct_ev_whitelist.h" -#include "net/cert/ct_policy_enforcer.h" -#include "net/cert/ct_policy_status.h" -#include "net/cert/ct_verifier.h" -#include "net/cert/ct_verify_result.h" -#include "net/cert/scoped_nss_types.h" -#include "net/cert/sct_status_flags.h" -#include "net/cert/x509_certificate_net_log_param.h" -#include "net/cert/x509_util.h" -#include "net/cert_net/nss_ocsp.h" -#include "net/dns/dns_util.h" -#include "net/http/transport_security_state.h" -#include "net/log/net_log.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/nss_ssl_util.h" -#include "net/ssl/ssl_cert_request_info.h" -#include "net/ssl/ssl_cipher_suite_names.h" -#include "net/ssl/ssl_connection_status_flags.h" -#include "net/ssl/ssl_failure_state.h" -#include "net/ssl/ssl_info.h" - -#if defined(USE_NSS_CERTS) -#include <dlfcn.h> -#endif - -namespace net { - -// State machines are easier to debug if you log state transitions. -// Enable these if you want to see what's going on. -#if 1 -#define EnterFunction(x) -#define LeaveFunction(x) -#define GotoState(s) next_handshake_state_ = s -#else -#define EnterFunction(x)\ - VLOG(1) << (void *)this << " " << __FUNCTION__ << " enter " << x\ - << "; next_handshake_state " << next_handshake_state_ -#define LeaveFunction(x)\ - VLOG(1) << (void *)this << " " << __FUNCTION__ << " leave " << x\ - << "; next_handshake_state " << next_handshake_state_ -#define GotoState(s)\ - do {\ - VLOG(1) << (void *)this << " " << __FUNCTION__ << " jump to state " << s;\ - next_handshake_state_ = s;\ - } while (0) -#endif - -namespace { - -// SSL plaintext fragments are shorter than 16KB. Although the record layer -// overhead is allowed to be 2K + 5 bytes, in practice the overhead is much -// smaller than 1KB. So a 17KB buffer should be large enough to hold an -// entire SSL record. -const int kRecvBufferSize = 17 * 1024; -const int kSendBufferSize = 17 * 1024; - -// Used by SSLClientSocketNSS::Core to indicate there is no read result -// obtained by a previous operation waiting to be returned to the caller. -// This constant can be any non-negative/non-zero value (eg: it does not -// overlap with any value of the net::Error range, including net::OK). -const int kNoPendingReadResult = 1; - -// Helper functions to make it possible to log events from within the -// SSLClientSocketNSS::Core. -void AddLogEvent(const base::WeakPtr<BoundNetLog>& net_log, - NetLog::EventType event_type) { - if (!net_log) - return; - net_log->AddEvent(event_type); -} - -// Helper function to make it possible to log events from within the -// SSLClientSocketNSS::Core. -void AddLogEventWithCallback(const base::WeakPtr<BoundNetLog>& net_log, - NetLog::EventType event_type, - const NetLog::ParametersCallback& callback) { - if (!net_log) - return; - net_log->AddEvent(event_type, callback); -} - -// Helper function to make it easier to call BoundNetLog::AddByteTransferEvent -// from within the SSLClientSocketNSS::Core. -// AddByteTransferEvent expects to receive a const char*, which within the -// Core is backed by an IOBuffer. If the "const char*" is bound via -// base::Bind and posted to another thread, and the IOBuffer that backs that -// pointer then goes out of scope on the origin thread, this would result in -// an invalid read of a stale pointer. -// Instead, provide a signature that accepts an IOBuffer*, so that a reference -// to the owning IOBuffer can be bound to the Callback. This ensures that the -// IOBuffer will stay alive long enough to cross threads if needed. -void LogByteTransferEvent( - const base::WeakPtr<BoundNetLog>& net_log, NetLog::EventType event_type, - int len, IOBuffer* buffer) { - if (!net_log) - return; - net_log->AddByteTransferEvent(event_type, len, buffer->data()); -} - -// PeerCertificateChain is a helper object which extracts the certificate -// chain, as given by the server, from an NSS socket and performs the needed -// resource management. The first element of the chain is the leaf certificate -// and the other elements are in the order given by the server. -class PeerCertificateChain { - public: - PeerCertificateChain() {} - PeerCertificateChain(const PeerCertificateChain& other); - ~PeerCertificateChain(); - PeerCertificateChain& operator=(const PeerCertificateChain& other); - - // Resets the current chain, freeing any resources, and updates the current - // chain to be a copy of the chain stored in |nss_fd|. - // If |nss_fd| is NULL, then the current certificate chain will be freed. - void Reset(PRFileDesc* nss_fd); - - // Returns the current certificate chain as a vector of DER-encoded - // base::StringPieces. The returned vector remains valid until Reset is - // called. - std::vector<base::StringPiece> AsStringPieceVector() const; - - bool empty() const { return certs_.empty(); } - - CERTCertificate* operator[](size_t index) const { - DCHECK_LT(index, certs_.size()); - return certs_[index]; - } - - private: - std::vector<CERTCertificate*> certs_; -}; - -PeerCertificateChain::PeerCertificateChain( - const PeerCertificateChain& other) { - *this = other; -} - -PeerCertificateChain::~PeerCertificateChain() { - Reset(NULL); -} - -PeerCertificateChain& PeerCertificateChain::operator=( - const PeerCertificateChain& other) { - if (this == &other) - return *this; - - Reset(NULL); - certs_.reserve(other.certs_.size()); - for (size_t i = 0; i < other.certs_.size(); ++i) - certs_.push_back(CERT_DupCertificate(other.certs_[i])); - - return *this; -} - -void PeerCertificateChain::Reset(PRFileDesc* nss_fd) { - for (size_t i = 0; i < certs_.size(); ++i) - CERT_DestroyCertificate(certs_[i]); - certs_.clear(); - - if (nss_fd == NULL) - return; - - CERTCertList* list = SSL_PeerCertificateChain(nss_fd); - // The handshake on |nss_fd| may not have completed. - if (list == NULL) - return; - - for (CERTCertListNode* node = CERT_LIST_HEAD(list); - !CERT_LIST_END(node, list); node = CERT_LIST_NEXT(node)) { - certs_.push_back(CERT_DupCertificate(node->cert)); - } - CERT_DestroyCertList(list); -} - -std::vector<base::StringPiece> -PeerCertificateChain::AsStringPieceVector() const { - std::vector<base::StringPiece> v(certs_.size()); - for (unsigned i = 0; i < certs_.size(); i++) { - v[i] = base::StringPiece( - reinterpret_cast<const char*>(certs_[i]->derCert.data), - certs_[i]->derCert.len); - } - - return v; -} - -// HandshakeState is a helper struct used to pass handshake state between -// the NSS task runner and the network task runner. -// -// It contains members that may be read or written on the NSS task runner, -// but which also need to be read from the network task runner. The NSS task -// runner will notify the network task runner whenever this state changes, so -// that the network task runner can safely make a copy, which avoids the need -// for locking. -struct HandshakeState { - HandshakeState() { Reset(); } - - void Reset() { - next_proto_status = SSLClientSocket::kNextProtoUnsupported; - next_proto.clear(); - negotiation_extension_ = SSLClientSocket::kExtensionUnknown; - channel_id_sent = false; - server_cert_chain.Reset(NULL); - server_cert = NULL; - sct_list_from_tls_extension.clear(); - stapled_ocsp_response.clear(); - resumed_handshake = false; - ssl_connection_status = 0; - } - - // Set to kNextProtoNegotiated if NPN was successfully negotiated, with the - // negotiated protocol stored in |next_proto|. - SSLClientSocket::NextProtoStatus next_proto_status; - std::string next_proto; - - // TLS extension used for protocol negotiation. - SSLClientSocket::SSLNegotiationExtension negotiation_extension_; - - // True if a channel ID was sent. - bool channel_id_sent; - - // List of DER-encoded X.509 DistinguishedName of certificate authorities - // allowed by the server. - std::vector<std::string> cert_authorities; - - // Set when the handshake fully completes. - // - // The server certificate is first received from NSS as an NSS certificate - // chain (|server_cert_chain|) and then converted into a platform-specific - // X509Certificate object (|server_cert|). It's possible for some - // certificates to be successfully parsed by NSS, and not by the platform - // libraries (i.e.: when running within a sandbox, different parsing - // algorithms, etc), so it's not safe to assume that |server_cert| will - // always be non-NULL. - PeerCertificateChain server_cert_chain; - scoped_refptr<X509Certificate> server_cert; - // SignedCertificateTimestampList received via TLS extension (RFC 6962). - std::string sct_list_from_tls_extension; - // Stapled OCSP response received. - std::string stapled_ocsp_response; - - // True if the current handshake was the result of TLS session resumption. - bool resumed_handshake; - - // The negotiated security parameters (TLS version, cipher, extensions) of - // the SSL connection. - int ssl_connection_status; -}; - -// Client-side error mapping functions. - -// Map NSS error code to network error code. -int MapNSSClientError(PRErrorCode err) { - switch (err) { - case SSL_ERROR_BAD_CERT_ALERT: - case SSL_ERROR_UNSUPPORTED_CERT_ALERT: - case SSL_ERROR_REVOKED_CERT_ALERT: - case SSL_ERROR_EXPIRED_CERT_ALERT: - case SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT: - case SSL_ERROR_UNKNOWN_CA_ALERT: - case SSL_ERROR_ACCESS_DENIED_ALERT: - return ERR_BAD_SSL_CLIENT_AUTH_CERT; - default: - return MapNSSError(err); - } -} - -} // namespace - -// SSLClientSocketNSS::Core provides a thread-safe, ref-counted core that is -// able to marshal data between NSS functions and an underlying transport -// socket. -// -// All public functions are meant to be called from the network task runner, -// and any callbacks supplied will be invoked there as well, provided that -// Detach() has not been called yet. -// -///////////////////////////////////////////////////////////////////////////// -// -// Threading within SSLClientSocketNSS and SSLClientSocketNSS::Core: -// -// Because NSS may block on either hardware or user input during operations -// such as signing, creating certificates, or locating private keys, the Core -// handles all of the interactions with the underlying NSS SSL socket, so -// that these blocking calls can be executed on a dedicated task runner. -// -// Note that the network task runner and the NSS task runner may be executing -// on the same thread. If that happens, then it's more performant to try to -// complete as much work as possible synchronously, even if it might block, -// rather than continually PostTask-ing to the same thread. -// -// Because NSS functions should only be called on the NSS task runner, while -// I/O resources should only be accessed on the network task runner, most -// public functions are implemented via three methods, each with different -// task runner affinities. -// -// In the single-threaded mode (where the network and NSS task runners run on -// the same thread), these are all attempted synchronously, while in the -// multi-threaded mode, message passing is used. -// -// 1) NSS Task Runner: Execute NSS function (DoPayloadRead, DoPayloadWrite, -// DoHandshake) -// 2) NSS Task Runner: Prepare data to go from NSS to an IO function: -// (BufferRecv, BufferSend) -// 3) Network Task Runner: Perform IO on that data (DoBufferRecv, -// DoBufferSend, DoGetChannelID, OnGetChannelIDComplete) -// 4) Both Task Runners: Callback for asynchronous completion or to marshal -// data from the network task runner back to NSS (BufferRecvComplete, -// BufferSendComplete, OnHandshakeIOComplete) -// -///////////////////////////////////////////////////////////////////////////// -// Single-threaded example -// -// |--------------------------Network Task Runner--------------------------| -// SSLClientSocketNSS Core (Transport Socket) -// Read() -// |-------------------------V -// Read() -// | -// DoPayloadRead() -// | -// BufferRecv() -// | -// DoBufferRecv() -// |-------------------------V -// Read() -// V-------------------------| -// BufferRecvComplete() -// | -// PostOrRunCallback() -// V-------------------------| -// (Read Callback) -// -///////////////////////////////////////////////////////////////////////////// -// Multi-threaded example: -// -// |--------------------Network Task Runner-------------|--NSS Task Runner--| -// SSLClientSocketNSS Core Socket Core -// Read() -// |---------------------V -// Read() -// |-------------------------------V -// Read() -// | -// DoPayloadRead() -// | -// BufferRecv -// V-------------------------------| -// DoBufferRecv -// |----------------V -// Read() -// V----------------| -// BufferRecvComplete() -// |-------------------------------V -// BufferRecvComplete() -// | -// PostOrRunCallback() -// V-------------------------------| -// PostOrRunCallback() -// V---------------------| -// (Read Callback) -// -///////////////////////////////////////////////////////////////////////////// -class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> { - public: - // Creates a new Core. - // - // Any calls to NSS are executed on the |nss_task_runner|, while any calls - // that need to operate on the underlying transport, net log, or server - // bound certificate fetching will happen on the |network_task_runner|, so - // that their lifetimes match that of the owning SSLClientSocketNSS. - // - // The caller retains ownership of |transport|, |net_log|, and - // |channel_id_service|, and they will not be accessed once Detach() - // has been called. - Core(base::SequencedTaskRunner* network_task_runner, - base::SequencedTaskRunner* nss_task_runner, - ClientSocketHandle* transport, - const HostPortPair& host_and_port, - const SSLConfig& ssl_config, - BoundNetLog* net_log, - ChannelIDService* channel_id_service); - - // Called on the network task runner. - // Transfers ownership of |socket|, an NSS SSL socket, and |buffers|, the - // underlying memio implementation, to the Core. Returns true if the Core - // was successfully registered with the socket. - bool Init(PRFileDesc* socket, memio_Private* buffers); - - // Called on the network task runner. - // - // Attempts to perform an SSL handshake. If the handshake cannot be - // completed synchronously, returns ERR_IO_PENDING, invoking |callback| on - // the network task runner once the handshake has completed. Otherwise, - // returns OK on success or a network error code on failure. - int Connect(const CompletionCallback& callback); - - // Called on the network task runner. - // Signals that the resources owned by the network task runner are going - // away. No further callbacks will be invoked on the network task runner. - // May be called at any time. - void Detach(); - - // Called on the network task runner. - // Returns the current state of the underlying SSL socket. May be called at - // any time. - const HandshakeState& state() const { return network_handshake_state_; } - - // Called on the network task runner. - // Read() and Write() mirror the net::Socket functions of the same name. - // If ERR_IO_PENDING is returned, |callback| will be invoked on the network - // task runner at a later point, unless the caller calls Detach(). - int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - - // Called on the network task runner. - bool IsConnected() const; - bool HasPendingAsyncOperation() const; - bool HasUnhandledReceivedData() const; - bool WasEverUsed() const; - - // Called on the network task runner. - // Causes the associated SSL/TLS session ID to be added to NSS's session - // cache, but only if the connection has not been False Started. - // - // This should only be called after the server's certificate has been - // verified, and may not be called within an NSS callback. - void CacheSessionIfNecessary(); - - crypto::ECPrivateKey* GetChannelIDKey() const { - return channel_id_key_.get(); - } - - private: - friend class base::RefCountedThreadSafe<Core>; - ~Core(); - - enum State { - STATE_NONE, - STATE_HANDSHAKE, - STATE_GET_DOMAIN_BOUND_CERT_COMPLETE, - }; - - bool OnNSSTaskRunner() const; - bool OnNetworkTaskRunner() const; - - //////////////////////////////////////////////////////////////////////////// - // Methods that are ONLY called on the NSS task runner: - //////////////////////////////////////////////////////////////////////////// - - // Called by NSS during full handshakes to allow the application to - // verify the certificate. Instead of verifying the certificate in the midst - // of the handshake, SECSuccess is always returned and the peer's certificate - // is verified afterwards. - // This behaviour is an artifact of the original SSLClientSocketWin - // implementation, which could not verify the peer's certificate until after - // the handshake had completed, as well as bugs in NSS that prevent - // SSL_RestartHandshakeAfterCertReq from working. - static SECStatus OwnAuthCertHandler(void* arg, - PRFileDesc* socket, - PRBool checksig, - PRBool is_server); - - // Callbacks called by NSS when the peer requests client certificate - // authentication. - // See the documentation in third_party/nss/ssl/ssl.h for the meanings of - // the arguments. - static SECStatus ClientAuthHandler(void* arg, - PRFileDesc* socket, - CERTDistNames* ca_names, - CERTCertificate** result_certificate, - SECKEYPrivateKey** result_private_key); - - // Called by NSS to determine if we can False Start. - // |arg| contains a pointer to the current SSLClientSocketNSS::Core. - static SECStatus CanFalseStartCallback(PRFileDesc* socket, - void* arg, - PRBool* can_false_start); - - // Called by NSS each time a handshake completely finishes. - // |arg| contains a pointer to the current SSLClientSocketNSS::Core. - static void HandshakeCallback(PRFileDesc* socket, void* arg); - - // Called once for each successful handshake. If the initial handshake false - // starts, it is called when it false starts and not when it completely - // finishes. is_initial is true if this is the initial handshake. - void HandshakeSucceeded(bool is_initial); - - // Handles an NSS error generated while handshaking or performing IO. - // Returns a network error code mapped from the original NSS error. - int HandleNSSError(PRErrorCode error); - - int DoHandshakeLoop(int last_io_result); - int DoReadLoop(int result); - int DoWriteLoop(int result); - - int DoHandshake(); - int DoGetDBCertComplete(int result); - - int DoPayloadRead(); - int DoPayloadWrite(); - - bool DoTransportIO(); - int BufferRecv(); - int BufferSend(); - - void OnRecvComplete(int result); - void OnSendComplete(int result); - - void DoConnectCallback(int result); - void DoReadCallback(int result); - void DoWriteCallback(int result); - - // Client channel ID handler. - static SECStatus ClientChannelIDHandler( - void* arg, - PRFileDesc* socket, - SECKEYPublicKey **out_public_key, - SECKEYPrivateKey **out_private_key); - - // ImportChannelIDKeys is a helper function for turning a DER-encoded cert and - // key into a SECKEYPublicKey and SECKEYPrivateKey. Returns OK upon success - // and an error code otherwise. - // Requires |domain_bound_private_key_| and |domain_bound_cert_| to have been - // set by a call to ChannelIDService->GetChannelID. The caller - // takes ownership of the |*cert| and |*key|. - int ImportChannelIDKeys(SECKEYPublicKey** public_key, SECKEYPrivateKey** key); - - // Updates the NSS and platform specific certificates. - void UpdateServerCert(); - // Update the nss_handshake_state_ with the SignedCertificateTimestampList - // received in the handshake via a TLS extension. - void UpdateSignedCertTimestamps(); - // Update the OCSP response cache with the stapled response received in the - // handshake, and update nss_handshake_state_ with - // the SignedCertificateTimestampList received in the stapled OCSP response. - void UpdateStapledOCSPResponse(); - // Updates the nss_handshake_state_ with the negotiated security parameters. - void UpdateConnectionStatus(); - // Record histograms for channel id support during full handshakes - resumed - // handshakes are ignored. - void RecordChannelIDSupportOnNSSTaskRunner(); - // UpdateNextProto gets any application-layer protocol that may have been - // negotiated by the TLS connection. - void UpdateNextProto(); - // Record TLS extension used for protocol negotiation (NPN or ALPN). - void UpdateExtensionUsed(); - - // Returns true if renegotiations are allowed. - bool IsRenegotiationAllowed() const; - - //////////////////////////////////////////////////////////////////////////// - // Methods that are ONLY called on the network task runner: - //////////////////////////////////////////////////////////////////////////// - int DoBufferRecv(IOBuffer* buffer, int len); - int DoBufferSend(IOBuffer* buffer, int len); - int DoGetChannelID(const std::string& host); - - void OnGetChannelIDComplete(int result); - void OnHandshakeStateUpdated(const HandshakeState& state); - void OnNSSBufferUpdated(int amount_in_read_buffer); - void DidNSSRead(int result); - void DidNSSWrite(int result); - void RecordChannelIDSupportOnNetworkTaskRunner(bool negotiated_channel_id, - bool channel_id_enabled) const; - - //////////////////////////////////////////////////////////////////////////// - // Methods that are called on both the network task runner and the NSS - // task runner. - //////////////////////////////////////////////////////////////////////////// - void OnHandshakeIOComplete(int result); - void BufferRecvComplete(IOBuffer* buffer, int result); - void BufferSendComplete(int result); - - // PostOrRunCallback is a helper function to ensure that |callback| is - // invoked on the network task runner, but only if Detach() has not yet - // been called. - void PostOrRunCallback(const tracked_objects::Location& location, - const base::Closure& callback); - - // Uses PostOrRunCallback and |weak_net_log_| to try and log a - // SSL_CLIENT_CERT_PROVIDED event, with the indicated count. - void AddCertProvidedEvent(int cert_count); - - // Sets the handshake state |channel_id_sent| flag and logs the - // SSL_CHANNEL_ID_PROVIDED event. - void SetChannelIDProvided(); - - //////////////////////////////////////////////////////////////////////////// - // Members that are ONLY accessed on the network task runner: - //////////////////////////////////////////////////////////////////////////// - - // True if the owning SSLClientSocketNSS has called Detach(). No further - // callbacks will be invoked nor access to members owned by the network - // task runner. - bool detached_; - - // The underlying transport to use for network IO. - ClientSocketHandle* transport_; - base::WeakPtrFactory<BoundNetLog> weak_net_log_factory_; - - // The current handshake state. Mirrors |nss_handshake_state_|. - HandshakeState network_handshake_state_; - - // The service for retrieving Channel ID keys. May be NULL. - ChannelIDService* channel_id_service_; - ChannelIDService::Request channel_id_request_; - - // The information about NSS task runner. - int unhandled_buffer_size_; - bool nss_waiting_read_; - bool nss_waiting_write_; - bool nss_is_closed_; - - // Set when Read() or Write() successfully reads or writes data to or from the - // network. - bool was_ever_used_; - - //////////////////////////////////////////////////////////////////////////// - // Members that are ONLY accessed on the NSS task runner: - //////////////////////////////////////////////////////////////////////////// - HostPortPair host_and_port_; - SSLConfig ssl_config_; - - // NSS SSL socket. - PRFileDesc* nss_fd_; - - // Buffers for the network end of the SSL state machine - memio_Private* nss_bufs_; - - // Used by DoPayloadRead() when attempting to fill the caller's buffer with - // as much data as possible, without blocking. - // If DoPayloadRead() encounters an error after having read some data, stores - // the results to return on the *next* call to DoPayloadRead(). A value of - // kNoPendingReadResult indicates there is no pending result, otherwise 0 - // indicates EOF and < 0 indicates an error. - int pending_read_result_; - // Contains the previously observed NSS error. Only valid when - // pending_read_result_ != kNoPendingReadResult. - PRErrorCode pending_read_nss_error_; - - // The certificate chain, in DER form, that is expected to be received from - // the server. - std::vector<std::string> predicted_certs_; - - State next_handshake_state_; - - // True if channel ID extension was negotiated. - bool channel_id_xtn_negotiated_; - // True if the handshake state machine was interrupted for channel ID. - bool channel_id_needed_; - // True if the handshake state machine was interrupted for client auth. - bool client_auth_cert_needed_; - // True if NSS has False Started in the initial handshake, but the initial - // handshake has not yet completely finished.. - bool false_started_; - // True if NSS has called HandshakeCallback. - bool handshake_callback_called_; - - HandshakeState nss_handshake_state_; - - bool transport_recv_busy_; - bool transport_recv_eof_; - bool transport_send_busy_; - - // Used by Read function. - scoped_refptr<IOBuffer> user_read_buf_; - int user_read_buf_len_; - - // Used by Write function. - scoped_refptr<IOBuffer> user_write_buf_; - int user_write_buf_len_; - - CompletionCallback user_connect_callback_; - CompletionCallback user_read_callback_; - CompletionCallback user_write_callback_; - - //////////////////////////////////////////////////////////////////////////// - // Members that are accessed on both the network task runner and the NSS - // task runner. - //////////////////////////////////////////////////////////////////////////// - scoped_refptr<base::SequencedTaskRunner> network_task_runner_; - scoped_refptr<base::SequencedTaskRunner> nss_task_runner_; - - // Dereferenced only on the network task runner, but bound to tasks destined - // for the network task runner from the NSS task runner. - base::WeakPtr<BoundNetLog> weak_net_log_; - - // Written on the network task runner by the |channel_id_service_|, - // prior to invoking OnHandshakeIOComplete. - // Read on the NSS task runner when once OnHandshakeIOComplete is invoked - // on the NSS task runner. - std::unique_ptr<crypto::ECPrivateKey> channel_id_key_; - - DISALLOW_COPY_AND_ASSIGN(Core); -}; - -SSLClientSocketNSS::Core::Core( - base::SequencedTaskRunner* network_task_runner, - base::SequencedTaskRunner* nss_task_runner, - ClientSocketHandle* transport, - const HostPortPair& host_and_port, - const SSLConfig& ssl_config, - BoundNetLog* net_log, - ChannelIDService* channel_id_service) - : detached_(false), - transport_(transport), - weak_net_log_factory_(net_log), - channel_id_service_(channel_id_service), - unhandled_buffer_size_(0), - nss_waiting_read_(false), - nss_waiting_write_(false), - nss_is_closed_(false), - was_ever_used_(false), - host_and_port_(host_and_port), - ssl_config_(ssl_config), - nss_fd_(NULL), - nss_bufs_(NULL), - pending_read_result_(kNoPendingReadResult), - pending_read_nss_error_(0), - next_handshake_state_(STATE_NONE), - channel_id_xtn_negotiated_(false), - channel_id_needed_(false), - client_auth_cert_needed_(false), - false_started_(false), - handshake_callback_called_(false), - transport_recv_busy_(false), - transport_recv_eof_(false), - transport_send_busy_(false), - user_read_buf_len_(0), - user_write_buf_len_(0), - network_task_runner_(network_task_runner), - nss_task_runner_(nss_task_runner), - weak_net_log_(weak_net_log_factory_.GetWeakPtr()) { -} - -SSLClientSocketNSS::Core::~Core() { - // TODO(wtc): Send SSL close_notify alert. - if (nss_fd_ != NULL) { - PR_Close(nss_fd_); - nss_fd_ = NULL; - } - nss_bufs_ = NULL; -} - -bool SSLClientSocketNSS::Core::Init(PRFileDesc* socket, - memio_Private* buffers) { - DCHECK(OnNetworkTaskRunner()); - DCHECK(!nss_fd_); - DCHECK(!nss_bufs_); - - nss_fd_ = socket; - nss_bufs_ = buffers; - - SECStatus rv = SECSuccess; - - if (!ssl_config_.alpn_protos.empty()) { - NextProtoVector alpn_protos = ssl_config_.alpn_protos; - // TODO(bnc): Check ssl_config_.disabled_cipher_suites. - if (!IsTLSVersionAdequateForHTTP2(ssl_config_)) - DisableHTTP2(&alpn_protos); - // |ssl_config_| has fallback protocol at the end of the list, but NSS - // expects fallback at the first place, thus protocols need to be reordered. - ReorderNextProtos(&alpn_protos); - // NSS only supports a single protocol vector to be used with ALPN and NPN. - // Because of this limitation, |alpn_prototos| will be used for both. - // However, it is possible to enable ALPN and NPN separately. - std::vector<uint8_t> wire_protos = SerializeNextProtos(alpn_protos); - rv = SSL_SetNextProtoNego( - nss_fd_, wire_protos.empty() ? NULL : &wire_protos[0], - wire_protos.size()); - if (rv != SECSuccess) - LogFailedNSSFunction(*weak_net_log_, "SSL_SetNextProtoNego", ""); - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_ALPN, PR_TRUE); - if (rv != SECSuccess) - LogFailedNSSFunction(*weak_net_log_, "SSL_OptionSet", "SSL_ENABLE_ALPN"); - if (!ssl_config_.npn_protos.empty()) { - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_NPN, PR_TRUE); - if (rv != SECSuccess) - LogFailedNSSFunction(*weak_net_log_, "SSL_OptionSet", "SSL_ENABLE_NPN"); - } - } - - rv = SSL_AuthCertificateHook( - nss_fd_, SSLClientSocketNSS::Core::OwnAuthCertHandler, this); - if (rv != SECSuccess) { - LogFailedNSSFunction(*weak_net_log_, "SSL_AuthCertificateHook", ""); - return false; - } - - rv = SSL_GetClientAuthDataHook( - nss_fd_, SSLClientSocketNSS::Core::ClientAuthHandler, this); - if (rv != SECSuccess) { - LogFailedNSSFunction(*weak_net_log_, "SSL_GetClientAuthDataHook", ""); - return false; - } - - if (IsChannelIDEnabled(ssl_config_, channel_id_service_)) { - rv = SSL_SetClientChannelIDCallback( - nss_fd_, SSLClientSocketNSS::Core::ClientChannelIDHandler, this); - if (rv != SECSuccess) { - LogFailedNSSFunction( - *weak_net_log_, "SSL_SetClientChannelIDCallback", ""); - } - } - - rv = SSL_SetCanFalseStartCallback( - nss_fd_, SSLClientSocketNSS::Core::CanFalseStartCallback, this); - if (rv != SECSuccess) { - LogFailedNSSFunction(*weak_net_log_, "SSL_SetCanFalseStartCallback", ""); - return false; - } - - rv = SSL_HandshakeCallback( - nss_fd_, SSLClientSocketNSS::Core::HandshakeCallback, this); - if (rv != SECSuccess) { - LogFailedNSSFunction(*weak_net_log_, "SSL_HandshakeCallback", ""); - return false; - } - - return true; -} - -int SSLClientSocketNSS::Core::Connect(const CompletionCallback& callback) { - if (!OnNSSTaskRunner()) { - DCHECK(!detached_); - bool posted = nss_task_runner_->PostTask( - FROM_HERE, - base::Bind(IgnoreResult(&Core::Connect), this, callback)); - return posted ? ERR_IO_PENDING : ERR_ABORTED; - } - - DCHECK(OnNSSTaskRunner()); - DCHECK_EQ(STATE_NONE, next_handshake_state_); - DCHECK(user_read_callback_.is_null()); - DCHECK(user_write_callback_.is_null()); - DCHECK(user_connect_callback_.is_null()); - DCHECK(!user_read_buf_.get()); - DCHECK(!user_write_buf_.get()); - - next_handshake_state_ = STATE_HANDSHAKE; - int rv = DoHandshakeLoop(OK); - if (rv == ERR_IO_PENDING) { - user_connect_callback_ = callback; - } else if (rv > OK) { - rv = OK; - } - if (rv != ERR_IO_PENDING && !OnNetworkTaskRunner()) { - PostOrRunCallback(FROM_HERE, base::Bind(callback, rv)); - return ERR_IO_PENDING; - } - - return rv; -} - -void SSLClientSocketNSS::Core::Detach() { - DCHECK(OnNetworkTaskRunner()); - - detached_ = true; - transport_ = NULL; - weak_net_log_factory_.InvalidateWeakPtrs(); - - network_handshake_state_.Reset(); - - channel_id_request_.Cancel(); -} - -int SSLClientSocketNSS::Core::Read(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { - if (!OnNSSTaskRunner()) { - DCHECK(OnNetworkTaskRunner()); - DCHECK(!detached_); - DCHECK(transport_); - DCHECK(!nss_waiting_read_); - - nss_waiting_read_ = true; - bool posted = nss_task_runner_->PostTask( - FROM_HERE, base::Bind(IgnoreResult(&Core::Read), this, - base::RetainedRef(buf), buf_len, callback)); - if (!posted) { - nss_is_closed_ = true; - nss_waiting_read_ = false; - } - return posted ? ERR_IO_PENDING : ERR_ABORTED; - } - - DCHECK(OnNSSTaskRunner()); - DCHECK(false_started_ || handshake_callback_called_); - DCHECK_EQ(STATE_NONE, next_handshake_state_); - DCHECK(user_read_callback_.is_null()); - DCHECK(user_connect_callback_.is_null()); - DCHECK(!user_read_buf_.get()); - DCHECK(nss_bufs_); - - user_read_buf_ = buf; - user_read_buf_len_ = buf_len; - - int rv = DoReadLoop(OK); - if (rv == ERR_IO_PENDING) { - if (OnNetworkTaskRunner()) - nss_waiting_read_ = true; - user_read_callback_ = callback; - } else { - user_read_buf_ = NULL; - user_read_buf_len_ = 0; - - if (!OnNetworkTaskRunner()) { - PostOrRunCallback(FROM_HERE, base::Bind(&Core::DidNSSRead, this, rv)); - PostOrRunCallback(FROM_HERE, base::Bind(callback, rv)); - return ERR_IO_PENDING; - } else { - DCHECK(!nss_waiting_read_); - if (rv <= 0) { - nss_is_closed_ = true; - } else { - was_ever_used_ = true; - } - } - } - - return rv; -} - -int SSLClientSocketNSS::Core::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { - if (!OnNSSTaskRunner()) { - DCHECK(OnNetworkTaskRunner()); - DCHECK(!detached_); - DCHECK(transport_); - DCHECK(!nss_waiting_write_); - - nss_waiting_write_ = true; - bool posted = nss_task_runner_->PostTask( - FROM_HERE, base::Bind(IgnoreResult(&Core::Write), this, - base::RetainedRef(buf), buf_len, callback)); - if (!posted) { - nss_is_closed_ = true; - nss_waiting_write_ = false; - } - return posted ? ERR_IO_PENDING : ERR_ABORTED; - } - - DCHECK(OnNSSTaskRunner()); - DCHECK(false_started_ || handshake_callback_called_); - DCHECK_EQ(STATE_NONE, next_handshake_state_); - DCHECK(user_write_callback_.is_null()); - DCHECK(user_connect_callback_.is_null()); - DCHECK(!user_write_buf_.get()); - DCHECK(nss_bufs_); - - user_write_buf_ = buf; - user_write_buf_len_ = buf_len; - - int rv = DoWriteLoop(OK); - if (rv == ERR_IO_PENDING) { - if (OnNetworkTaskRunner()) - nss_waiting_write_ = true; - user_write_callback_ = callback; - } else { - user_write_buf_ = NULL; - user_write_buf_len_ = 0; - - if (!OnNetworkTaskRunner()) { - PostOrRunCallback(FROM_HERE, base::Bind(&Core::DidNSSWrite, this, rv)); - PostOrRunCallback(FROM_HERE, base::Bind(callback, rv)); - return ERR_IO_PENDING; - } else { - DCHECK(!nss_waiting_write_); - if (rv < 0) { - nss_is_closed_ = true; - } else if (rv > 0) { - was_ever_used_ = true; - } - } - } - - return rv; -} - -bool SSLClientSocketNSS::Core::IsConnected() const { - DCHECK(OnNetworkTaskRunner()); - return !nss_is_closed_; -} - -bool SSLClientSocketNSS::Core::HasPendingAsyncOperation() const { - DCHECK(OnNetworkTaskRunner()); - return nss_waiting_read_ || nss_waiting_write_; -} - -bool SSLClientSocketNSS::Core::HasUnhandledReceivedData() const { - DCHECK(OnNetworkTaskRunner()); - return unhandled_buffer_size_ != 0; -} - -bool SSLClientSocketNSS::Core::WasEverUsed() const { - DCHECK(OnNetworkTaskRunner()); - return was_ever_used_; -} - -void SSLClientSocketNSS::Core::CacheSessionIfNecessary() { - // TODO(rsleevi): This should occur on the NSS task runner, due to the use of - // nss_fd_. However, it happens on the network task runner in order to match - // the buggy behavior of ExportKeyingMaterial. - // - // Once http://crbug.com/330360 is fixed, this should be moved to an - // implementation that exclusively does this work on the NSS TaskRunner. This - // is "safe" because it is only called during the certificate verification - // state machine of the main socket, which is safe because no underlying - // transport IO will be occuring in that state, and NSS will not be blocking - // on any PKCS#11 related locks that might block the Network TaskRunner. - DCHECK(OnNetworkTaskRunner()); - - // Only cache the session if the connection was not False Started, because - // sessions should only be cached *after* the peer's Finished message is - // processed. - // In the case of False Start, the session will be cached once the - // HandshakeCallback is called, which signals the receipt and processing of - // the Finished message, and which will happen during a call to - // PR_Read/PR_Write. - if (!false_started_) - SSL_CacheSession(nss_fd_); -} - -bool SSLClientSocketNSS::Core::OnNSSTaskRunner() const { - return nss_task_runner_->RunsTasksOnCurrentThread(); -} - -bool SSLClientSocketNSS::Core::OnNetworkTaskRunner() const { - return network_task_runner_->RunsTasksOnCurrentThread(); -} - -// static -SECStatus SSLClientSocketNSS::Core::OwnAuthCertHandler( - void* arg, - PRFileDesc* socket, - PRBool checksig, - PRBool is_server) { - Core* core = reinterpret_cast<Core*>(arg); - if (core->handshake_callback_called_) { - // Disallow the server certificate to change in a renegotiation. - CERTCertificate* old_cert = core->nss_handshake_state_.server_cert_chain[0]; - ScopedCERTCertificate new_cert(SSL_PeerCertificate(socket)); - if (new_cert->derCert.len != old_cert->derCert.len || - memcmp(new_cert->derCert.data, old_cert->derCert.data, - new_cert->derCert.len) != 0) { - // NSS doesn't have an error code that indicates the server certificate - // changed. Borrow SSL_ERROR_WRONG_CERTIFICATE (which NSS isn't using) - // for this purpose. - PORT_SetError(SSL_ERROR_WRONG_CERTIFICATE); - return SECFailure; - } - } - - // Tell NSS to not verify the certificate. - return SECSuccess; -} - -#if defined(OS_IOS) - -// static -SECStatus SSLClientSocketNSS::Core::ClientAuthHandler( - void* arg, - PRFileDesc* socket, - CERTDistNames* ca_names, - CERTCertificate** result_certificate, - SECKEYPrivateKey** result_private_key) { - Core* core = reinterpret_cast<Core*>(arg); - DCHECK(core->OnNSSTaskRunner()); - - core->PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEvent, core->weak_net_log_, - NetLog::TYPE_SSL_CLIENT_CERT_REQUESTED)); - - // TODO(droger): Support client auth on iOS. See http://crbug.com/145954). - LOG(WARNING) << "Client auth is not supported"; - - // Never send a certificate. - core->AddCertProvidedEvent(0); - return SECFailure; -} - -#else // !OS_IOS - -// static -// Based on Mozilla's NSS_GetClientAuthData. -SECStatus SSLClientSocketNSS::Core::ClientAuthHandler( - void* arg, - PRFileDesc* socket, - CERTDistNames* ca_names, - CERTCertificate** result_certificate, - SECKEYPrivateKey** result_private_key) { - Core* core = reinterpret_cast<Core*>(arg); - DCHECK(core->OnNSSTaskRunner()); - - core->PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEvent, core->weak_net_log_, - NetLog::TYPE_SSL_CLIENT_CERT_REQUESTED)); - - // Regular client certificate requested. - core->client_auth_cert_needed_ = !core->ssl_config_.send_client_cert; - void* wincx = SSL_RevealPinArg(socket); - - if (core->ssl_config_.send_client_cert) { - // Second pass: a client certificate should have been selected. - if (core->ssl_config_.client_cert.get()) { - CERTCertificate* cert = - CERT_DupCertificate(core->ssl_config_.client_cert->os_cert_handle()); - SECKEYPrivateKey* privkey = PK11_FindKeyByAnyCert(cert, wincx); - if (privkey) { - // TODO(jsorianopastor): We should wait for server certificate - // verification before sending our credentials. See - // http://crbug.com/13934. - *result_certificate = cert; - *result_private_key = privkey; - // A cert_count of -1 means the number of certificates is unknown. - // NSS will construct the certificate chain. - core->AddCertProvidedEvent(-1); - - return SECSuccess; - } - LOG(WARNING) << "Client cert found without private key"; - } - // Send no client certificate. - core->AddCertProvidedEvent(0); - return SECFailure; - } - - // First pass: client certificate is needed. - core->nss_handshake_state_.cert_authorities.clear(); - - // Retrieve the DER-encoded DistinguishedName of the cert issuers accepted by - // the server and save them in |cert_authorities|. - for (int i = 0; i < ca_names->nnames; i++) { - core->nss_handshake_state_.cert_authorities.push_back(std::string( - reinterpret_cast<const char*>(ca_names->names[i].data), - static_cast<size_t>(ca_names->names[i].len))); - } - - // Update the network task runner's view of the handshake state now that - // server certificate request has been recorded. - core->PostOrRunCallback( - FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, core, - core->nss_handshake_state_)); - - // Tell NSS to suspend the client authentication. We will then abort the - // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED. - return SECWouldBlock; -} -#endif // OS_IOS - -// static -SECStatus SSLClientSocketNSS::Core::CanFalseStartCallback( - PRFileDesc* socket, - void* arg, - PRBool* can_false_start) { - // If the server doesn't support NPN or ALPN, then we don't do False - // Start with it. - PRBool negotiated_extension; - SECStatus rv = SSL_HandshakeNegotiatedExtension(socket, - ssl_app_layer_protocol_xtn, - &negotiated_extension); - if (rv != SECSuccess || !negotiated_extension) { - rv = SSL_HandshakeNegotiatedExtension(socket, - ssl_next_proto_nego_xtn, - &negotiated_extension); - } - if (rv != SECSuccess || !negotiated_extension) { - *can_false_start = PR_FALSE; - return SECSuccess; - } - - SSLChannelInfo channel_info; - SECStatus ok = - SSL_GetChannelInfo(socket, &channel_info, sizeof(channel_info)); - if (ok != SECSuccess || channel_info.length != sizeof(channel_info) || - channel_info.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2 || - !IsSecureTLSCipherSuite(channel_info.cipherSuite)) { - *can_false_start = PR_FALSE; - return SECSuccess; - } - - return SSL_RecommendedCanFalseStart(socket, can_false_start); -} - -// static -void SSLClientSocketNSS::Core::HandshakeCallback( - PRFileDesc* socket, - void* arg) { - Core* core = reinterpret_cast<Core*>(arg); - DCHECK(core->OnNSSTaskRunner()); - - bool is_initial = !core->handshake_callback_called_; - core->handshake_callback_called_ = true; - if (core->false_started_) { - core->false_started_ = false; - // If the connection was False Started, then at the time of this callback, - // the peer's certificate will have been verified or the caller will have - // accepted the error. - // This is guaranteed when using False Start because this callback will - // not be invoked until processing the peer's Finished message, which - // will only happen in a PR_Read/PR_Write call, which can only happen - // after the peer's certificate is verified. - SSL_CacheSessionUnlocked(socket); - - // Additionally, when False Starting, DoHandshake() will have already - // called HandshakeSucceeded(), so return now. - return; - } - core->HandshakeSucceeded(is_initial); -} - -void SSLClientSocketNSS::Core::HandshakeSucceeded(bool is_initial) { - DCHECK(OnNSSTaskRunner()); - - PRBool last_handshake_resumed; - SECStatus rv = SSL_HandshakeResumedSession(nss_fd_, &last_handshake_resumed); - if (rv == SECSuccess && last_handshake_resumed) { - nss_handshake_state_.resumed_handshake = true; - } else { - nss_handshake_state_.resumed_handshake = false; - } - - RecordChannelIDSupportOnNSSTaskRunner(); - UpdateServerCert(); - UpdateSignedCertTimestamps(); - UpdateStapledOCSPResponse(); - UpdateConnectionStatus(); - UpdateNextProto(); - UpdateExtensionUsed(); - - if (is_initial && IsRenegotiationAllowed()) { - // For compatibility, do not enforce RFC 5746 support. Per section 4.1, - // enforcement falls largely on the server. - // - // This is done in a callback rather than after SSL_ForceHandshake returns - // because SSL_ForceHandshake will otherwise greedly consume renegotiations - // before returning if Finished and HelloRequest are in the same - // record. - // - // Note that SSL_OptionSet should only be called for an initial - // handshake. See https://crbug.com/125299. - SECStatus rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_RENEGOTIATION, - SSL_RENEGOTIATE_TRANSITIONAL); - DCHECK_EQ(SECSuccess, rv); - } - - // Update the network task runners view of the handshake state whenever - // a handshake has completed. - PostOrRunCallback( - FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, this, - nss_handshake_state_)); -} - -int SSLClientSocketNSS::Core::HandleNSSError(PRErrorCode nss_error) { - DCHECK(OnNSSTaskRunner()); - - return MapNSSClientError(nss_error); -} - -int SSLClientSocketNSS::Core::DoHandshakeLoop(int last_io_result) { - DCHECK(OnNSSTaskRunner()); - - int rv = last_io_result; - do { - // Default to STATE_NONE for next state. - State state = next_handshake_state_; - GotoState(STATE_NONE); - - switch (state) { - case STATE_HANDSHAKE: - rv = DoHandshake(); - break; - case STATE_GET_DOMAIN_BOUND_CERT_COMPLETE: - rv = DoGetDBCertComplete(rv); - break; - case STATE_NONE: - default: - rv = ERR_UNEXPECTED; - LOG(DFATAL) << "unexpected state " << state; - break; - } - - // Do the actual network I/O - bool network_moved = DoTransportIO(); - if (network_moved && next_handshake_state_ == STATE_HANDSHAKE) { - // In general we exit the loop if rv is ERR_IO_PENDING. In this - // special case we keep looping even if rv is ERR_IO_PENDING because - // the transport IO may allow DoHandshake to make progress. - DCHECK(rv == OK || rv == ERR_IO_PENDING); - rv = OK; // This causes us to stay in the loop. - } - } while (rv != ERR_IO_PENDING && next_handshake_state_ != STATE_NONE); - return rv; -} - -int SSLClientSocketNSS::Core::DoReadLoop(int result) { - DCHECK(OnNSSTaskRunner()); - DCHECK(false_started_ || handshake_callback_called_); - DCHECK_EQ(STATE_NONE, next_handshake_state_); - - if (result < 0) - return result; - - if (!nss_bufs_) { - LOG(DFATAL) << "!nss_bufs_"; - int rv = ERR_UNEXPECTED; - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_READ_ERROR, - CreateNetLogSSLErrorCallback(rv, 0))); - return rv; - } - - bool network_moved; - int rv; - do { - rv = DoPayloadRead(); - network_moved = DoTransportIO(); - } while (rv == ERR_IO_PENDING && network_moved); - - return rv; -} - -int SSLClientSocketNSS::Core::DoWriteLoop(int result) { - DCHECK(OnNSSTaskRunner()); - DCHECK(false_started_ || handshake_callback_called_); - DCHECK_EQ(STATE_NONE, next_handshake_state_); - - if (result < 0) - return result; - - if (!nss_bufs_) { - LOG(DFATAL) << "!nss_bufs_"; - int rv = ERR_UNEXPECTED; - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_READ_ERROR, - CreateNetLogSSLErrorCallback(rv, 0))); - return rv; - } - - bool network_moved; - int rv; - do { - rv = DoPayloadWrite(); - network_moved = DoTransportIO(); - } while (rv == ERR_IO_PENDING && network_moved); - - LeaveFunction(rv); - return rv; -} - -int SSLClientSocketNSS::Core::DoHandshake() { - DCHECK(OnNSSTaskRunner()); - - int net_error = OK; - SECStatus rv = SSL_ForceHandshake(nss_fd_); - - // Note: this function may be called multiple times during the handshake, so - // even though channel id and client auth are separate else cases, they can - // both be used during a single SSL handshake. - if (channel_id_needed_) { - GotoState(STATE_GET_DOMAIN_BOUND_CERT_COMPLETE); - net_error = ERR_IO_PENDING; - } else if (client_auth_cert_needed_) { - net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_HANDSHAKE_ERROR, - CreateNetLogSSLErrorCallback(net_error, 0))); - } else if (rv == SECSuccess) { - if (!handshake_callback_called_) { - false_started_ = true; - HandshakeSucceeded(true); - } - } else { - PRErrorCode prerr = PR_GetError(); - net_error = HandleNSSError(prerr); - - // If not done, stay in this state - if (net_error == ERR_IO_PENDING) { - GotoState(STATE_HANDSHAKE); - } else { - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_HANDSHAKE_ERROR, - CreateNetLogSSLErrorCallback(net_error, prerr))); - } - } - - return net_error; -} - -int SSLClientSocketNSS::Core::DoGetDBCertComplete(int result) { - SECStatus rv; - PostOrRunCallback( - FROM_HERE, - base::Bind(&BoundNetLog::EndEventWithNetErrorCode, weak_net_log_, - NetLog::TYPE_SSL_GET_DOMAIN_BOUND_CERT, result)); - - channel_id_needed_ = false; - - if (result != OK) - return result; - - SECKEYPublicKey* public_key; - SECKEYPrivateKey* private_key; - int error = ImportChannelIDKeys(&public_key, &private_key); - if (error != OK) - return error; - - rv = SSL_RestartHandshakeAfterChannelIDReq(nss_fd_, public_key, private_key); - if (rv != SECSuccess) - return MapNSSError(PORT_GetError()); - - SetChannelIDProvided(); - GotoState(STATE_HANDSHAKE); - return OK; -} - -int SSLClientSocketNSS::Core::DoPayloadRead() { - DCHECK(OnNSSTaskRunner()); - DCHECK(user_read_buf_.get()); - DCHECK_GT(user_read_buf_len_, 0); - - int rv; - // If a previous greedy read resulted in an error that was not consumed (eg: - // due to the caller having read some data successfully), then return that - // pending error now. - if (pending_read_result_ != kNoPendingReadResult) { - rv = pending_read_result_; - PRErrorCode prerr = pending_read_nss_error_; - pending_read_result_ = kNoPendingReadResult; - pending_read_nss_error_ = 0; - - if (rv == 0) { - PostOrRunCallback(FROM_HERE, - base::Bind(&LogByteTransferEvent, weak_net_log_, - NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv, - base::RetainedRef(user_read_buf_))); - } else { - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_READ_ERROR, - CreateNetLogSSLErrorCallback(rv, prerr))); - } - return rv; - } - - // Perform a greedy read, attempting to read as much as the caller has - // requested. In the current NSS implementation, PR_Read will return - // exactly one SSL application data record's worth of data per invocation. - // The record size is dictated by the server, and may be noticeably smaller - // than the caller's buffer. This may be as little as a single byte, if the - // server is performing 1/n-1 record splitting. - // - // However, this greedy read may result in renegotiations/re-handshakes - // happening or may lead to some data being read, followed by an EOF (such as - // a TLS close-notify). If at least some data was read, then that result - // should be deferred until the next call to DoPayloadRead(). Otherwise, if no - // data was read, it's safe to return the error or EOF immediately. - int total_bytes_read = 0; - do { - rv = PR_Read(nss_fd_, user_read_buf_->data() + total_bytes_read, - user_read_buf_len_ - total_bytes_read); - if (rv > 0) - total_bytes_read += rv; - } while (total_bytes_read < user_read_buf_len_ && rv > 0); - int amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); - PostOrRunCallback(FROM_HERE, base::Bind(&Core::OnNSSBufferUpdated, this, - amount_in_read_buffer)); - - if (total_bytes_read == user_read_buf_len_) { - // The caller's entire request was satisfied without error. No further - // processing needed. - rv = total_bytes_read; - } else { - // Otherwise, an error occurred (rv <= 0). The error needs to be handled - // immediately, while the NSPR/NSS errors are still available in - // thread-local storage. However, the handled/remapped error code should - // only be returned if no application data was already read; if it was, the - // error code should be deferred until the next call of DoPayloadRead. - // - // If no data was read, |*next_result| will point to the return value of - // this function. If at least some data was read, |*next_result| will point - // to |pending_read_error_|, to be returned in a future call to - // DoPayloadRead() (e.g.: after the current data is handled). - int* next_result = &rv; - if (total_bytes_read > 0) { - pending_read_result_ = rv; - rv = total_bytes_read; - next_result = &pending_read_result_; - } - - if (client_auth_cert_needed_) { - *next_result = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; - pending_read_nss_error_ = 0; - } else if (*next_result < 0) { - // If *next_result == 0, then that indicates EOF, and no special error - // handling is needed. - pending_read_nss_error_ = PR_GetError(); - *next_result = HandleNSSError(pending_read_nss_error_); - if (rv > 0 && *next_result == ERR_IO_PENDING) { - // If at least some data was read from PR_Read(), do not treat - // insufficient data as an error to return in the next call to - // DoPayloadRead() - instead, let the call fall through to check - // PR_Read() again. This is because DoTransportIO() may complete - // in between the next call to DoPayloadRead(), and thus it is - // important to check PR_Read() on subsequent invocations to see - // if a complete record may now be read. - pending_read_nss_error_ = 0; - pending_read_result_ = kNoPendingReadResult; - } - } - } - - DCHECK_NE(ERR_IO_PENDING, pending_read_result_); - - if (rv >= 0) { - PostOrRunCallback(FROM_HERE, - base::Bind(&LogByteTransferEvent, weak_net_log_, - NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv, - base::RetainedRef(user_read_buf_))); - } else if (rv != ERR_IO_PENDING) { - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_READ_ERROR, - CreateNetLogSSLErrorCallback(rv, pending_read_nss_error_))); - pending_read_nss_error_ = 0; - } - return rv; -} - -int SSLClientSocketNSS::Core::DoPayloadWrite() { - DCHECK(OnNSSTaskRunner()); - - DCHECK(user_write_buf_.get()); - - int old_amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); - int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_); - int new_amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); - // PR_Write could potentially consume the unhandled data in the memio read - // buffer if a renegotiation is in progress. If the buffer is consumed, - // notify the latest buffer size to NetworkRunner. - if (old_amount_in_read_buffer != new_amount_in_read_buffer) { - PostOrRunCallback( - FROM_HERE, - base::Bind(&Core::OnNSSBufferUpdated, this, new_amount_in_read_buffer)); - } - if (rv >= 0) { - PostOrRunCallback(FROM_HERE, - base::Bind(&LogByteTransferEvent, weak_net_log_, - NetLog::TYPE_SSL_SOCKET_BYTES_SENT, rv, - base::RetainedRef(user_write_buf_))); - return rv; - } - PRErrorCode prerr = PR_GetError(); - if (prerr == PR_WOULD_BLOCK_ERROR) - return ERR_IO_PENDING; - - rv = HandleNSSError(prerr); - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_WRITE_ERROR, - CreateNetLogSSLErrorCallback(rv, prerr))); - return rv; -} - -// Do as much network I/O as possible between the buffer and the -// transport socket. Return true if some I/O performed, false -// otherwise (error or ERR_IO_PENDING). -bool SSLClientSocketNSS::Core::DoTransportIO() { - DCHECK(OnNSSTaskRunner()); - - bool network_moved = false; - if (nss_bufs_ != NULL) { - int rv; - // Read and write as much data as we can. The loop is neccessary - // because Write() may return synchronously. - do { - rv = BufferSend(); - if (rv != ERR_IO_PENDING && rv != 0) - network_moved = true; - } while (rv > 0); - if (!transport_recv_eof_ && BufferRecv() != ERR_IO_PENDING) - network_moved = true; - } - return network_moved; -} - -int SSLClientSocketNSS::Core::BufferRecv() { - DCHECK(OnNSSTaskRunner()); - - if (transport_recv_busy_) - return ERR_IO_PENDING; - - // If NSS is blocked on reading from |nss_bufs_|, because it is empty, - // determine how much data NSS wants to read. If NSS was not blocked, - // this will return 0. - int requested = memio_GetReadRequest(nss_bufs_); - if (requested == 0) { - // This is not a perfect match of error codes, as no operation is - // actually pending. However, returning 0 would be interpreted as a - // possible sign of EOF, which is also an inappropriate match. - return ERR_IO_PENDING; - } - - char* buf; - int nb = memio_GetReadParams(nss_bufs_, &buf); - int rv; - if (!nb) { - // buffer too full to read into, so no I/O possible at moment - rv = ERR_IO_PENDING; - } else { - scoped_refptr<IOBuffer> read_buffer(new IOBuffer(nb)); - if (OnNetworkTaskRunner()) { - rv = DoBufferRecv(read_buffer.get(), nb); - } else { - bool posted = network_task_runner_->PostTask( - FROM_HERE, base::Bind(IgnoreResult(&Core::DoBufferRecv), this, - base::RetainedRef(read_buffer), nb)); - rv = posted ? ERR_IO_PENDING : ERR_ABORTED; - } - - if (rv == ERR_IO_PENDING) { - transport_recv_busy_ = true; - } else { - if (rv > 0) { - memcpy(buf, read_buffer->data(), rv); - } else if (rv == 0) { - transport_recv_eof_ = true; - } - memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv)); - } - } - return rv; -} - -// Return 0 if nss_bufs_ was empty, -// > 0 for bytes transferred immediately, -// < 0 for error (or the non-error ERR_IO_PENDING). -int SSLClientSocketNSS::Core::BufferSend() { - DCHECK(OnNSSTaskRunner()); - - if (transport_send_busy_) - return ERR_IO_PENDING; - - const char* buf1; - const char* buf2; - unsigned int len1, len2; - if (memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2)) { - // It is important this return synchronously to prevent spinning infinitely - // in the off-thread NSS case. The error code itself is ignored, so just - // return ERR_ABORTED. See https://crbug.com/381160. - return ERR_ABORTED; - } - const size_t len = len1 + len2; - - int rv = 0; - if (len) { - scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len)); - memcpy(send_buffer->data(), buf1, len1); - memcpy(send_buffer->data() + len1, buf2, len2); - - if (OnNetworkTaskRunner()) { - rv = DoBufferSend(send_buffer.get(), len); - } else { - bool posted = network_task_runner_->PostTask( - FROM_HERE, base::Bind(IgnoreResult(&Core::DoBufferSend), this, - base::RetainedRef(send_buffer), len)); - rv = posted ? ERR_IO_PENDING : ERR_ABORTED; - } - - if (rv == ERR_IO_PENDING) { - transport_send_busy_ = true; - } else { - memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv)); - } - } - - return rv; -} - -void SSLClientSocketNSS::Core::OnRecvComplete(int result) { - DCHECK(OnNSSTaskRunner()); - - if (next_handshake_state_ == STATE_HANDSHAKE) { - OnHandshakeIOComplete(result); - return; - } - - // Network layer received some data, check if client requested to read - // decrypted data. - if (!user_read_buf_.get()) - return; - - int rv = DoReadLoop(result); - if (rv != ERR_IO_PENDING) - DoReadCallback(rv); -} - -void SSLClientSocketNSS::Core::OnSendComplete(int result) { - DCHECK(OnNSSTaskRunner()); - - if (next_handshake_state_ == STATE_HANDSHAKE) { - OnHandshakeIOComplete(result); - return; - } - - // OnSendComplete may need to call DoPayloadRead while the renegotiation - // handshake is in progress. - int rv_read = ERR_IO_PENDING; - int rv_write = ERR_IO_PENDING; - bool network_moved; - do { - if (user_read_buf_.get()) - rv_read = DoPayloadRead(); - if (user_write_buf_.get()) - rv_write = DoPayloadWrite(); - network_moved = DoTransportIO(); - } while (rv_read == ERR_IO_PENDING && rv_write == ERR_IO_PENDING && - (user_read_buf_.get() || user_write_buf_.get()) && network_moved); - - // If the parent SSLClientSocketNSS is deleted during the processing of the - // Read callback and OnNSSTaskRunner() == OnNetworkTaskRunner(), then the Core - // will be detached (and possibly deleted). Guard against deletion by taking - // an extra reference, then check if the Core was detached before invoking the - // next callback. - scoped_refptr<Core> guard(this); - if (user_read_buf_.get() && rv_read != ERR_IO_PENDING) - DoReadCallback(rv_read); - - if (OnNetworkTaskRunner() && detached_) - return; - - if (user_write_buf_.get() && rv_write != ERR_IO_PENDING) - DoWriteCallback(rv_write); -} - -// As part of Connect(), the SSLClientSocketNSS object performs an SSL -// handshake. This requires network IO, which in turn calls -// BufferRecvComplete() with a non-zero byte count. This byte count eventually -// winds its way through the state machine and ends up being passed to the -// callback. For Read() and Write(), that's what we want. But for Connect(), -// the caller expects OK (i.e. 0) for success. -void SSLClientSocketNSS::Core::DoConnectCallback(int rv) { - DCHECK(OnNSSTaskRunner()); - DCHECK_NE(rv, ERR_IO_PENDING); - DCHECK(!user_connect_callback_.is_null()); - - base::Closure c = base::Bind( - base::ResetAndReturn(&user_connect_callback_), - rv > OK ? OK : rv); - PostOrRunCallback(FROM_HERE, c); -} - -void SSLClientSocketNSS::Core::DoReadCallback(int rv) { - DCHECK(OnNSSTaskRunner()); - DCHECK_NE(ERR_IO_PENDING, rv); - DCHECK(!user_read_callback_.is_null()); - - user_read_buf_ = NULL; - user_read_buf_len_ = 0; - int amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); - // This is used to curry the |amount_int_read_buffer| and |user_cb| back to - // the network task runner. - PostOrRunCallback( - FROM_HERE, - base::Bind(&Core::OnNSSBufferUpdated, this, amount_in_read_buffer)); - PostOrRunCallback( - FROM_HERE, - base::Bind(&Core::DidNSSRead, this, rv)); - PostOrRunCallback( - FROM_HERE, - base::Bind(base::ResetAndReturn(&user_read_callback_), rv)); -} - -void SSLClientSocketNSS::Core::DoWriteCallback(int rv) { - DCHECK(OnNSSTaskRunner()); - DCHECK_NE(ERR_IO_PENDING, rv); - DCHECK(!user_write_callback_.is_null()); - - // Since Run may result in Write being called, clear |user_write_callback_| - // up front. - user_write_buf_ = NULL; - user_write_buf_len_ = 0; - // Update buffer status because DoWriteLoop called DoTransportIO which may - // perform read operations. - int amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); - // This is used to curry the |amount_int_read_buffer| and |user_cb| back to - // the network task runner. - PostOrRunCallback( - FROM_HERE, - base::Bind(&Core::OnNSSBufferUpdated, this, amount_in_read_buffer)); - PostOrRunCallback( - FROM_HERE, - base::Bind(&Core::DidNSSWrite, this, rv)); - PostOrRunCallback( - FROM_HERE, - base::Bind(base::ResetAndReturn(&user_write_callback_), rv)); -} - -SECStatus SSLClientSocketNSS::Core::ClientChannelIDHandler( - void* arg, - PRFileDesc* socket, - SECKEYPublicKey **out_public_key, - SECKEYPrivateKey **out_private_key) { - Core* core = reinterpret_cast<Core*>(arg); - DCHECK(core->OnNSSTaskRunner()); - - core->PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEvent, core->weak_net_log_, - NetLog::TYPE_SSL_CHANNEL_ID_REQUESTED)); - - // We have negotiated the TLS channel ID extension. - core->channel_id_xtn_negotiated_ = true; - std::string host = core->host_and_port_.host(); - int error = ERR_UNEXPECTED; - if (core->OnNetworkTaskRunner()) { - error = core->DoGetChannelID(host); - } else { - bool posted = core->network_task_runner_->PostTask( - FROM_HERE, - base::Bind( - IgnoreResult(&Core::DoGetChannelID), - core, host)); - error = posted ? ERR_IO_PENDING : ERR_ABORTED; - } - - if (error == ERR_IO_PENDING) { - // Asynchronous case. - core->channel_id_needed_ = true; - return SECWouldBlock; - } - - core->PostOrRunCallback( - FROM_HERE, - base::Bind(&BoundNetLog::EndEventWithNetErrorCode, core->weak_net_log_, - NetLog::TYPE_SSL_GET_DOMAIN_BOUND_CERT, error)); - SECStatus rv = SECSuccess; - if (error == OK) { - // Synchronous success. - int result = core->ImportChannelIDKeys(out_public_key, out_private_key); - if (result == OK) - core->SetChannelIDProvided(); - else - rv = SECFailure; - } else { - rv = SECFailure; - } - - return rv; -} - -int SSLClientSocketNSS::Core::ImportChannelIDKeys(SECKEYPublicKey** public_key, - SECKEYPrivateKey** key) { - if (!channel_id_key_) - return SECFailure; - - *public_key = SECKEY_CopyPublicKey(channel_id_key_->public_key()); - *key = SECKEY_CopyPrivateKey(channel_id_key_->key()); - - return OK; -} - -void SSLClientSocketNSS::Core::UpdateServerCert() { - nss_handshake_state_.server_cert_chain.Reset(nss_fd_); - nss_handshake_state_.server_cert = X509Certificate::CreateFromDERCertChain( - nss_handshake_state_.server_cert_chain.AsStringPieceVector()); - if (nss_handshake_state_.server_cert.get()) { - // Since this will be called asynchronously on another thread, it needs to - // own a reference to the certificate. - NetLog::ParametersCallback net_log_callback = - base::Bind(&NetLogX509CertificateCallback, - base::RetainedRef(nss_handshake_state_.server_cert)); - PostOrRunCallback( - FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_CERTIFICATES_RECEIVED, - net_log_callback)); - } -} - -void SSLClientSocketNSS::Core::UpdateSignedCertTimestamps() { - const SECItem* signed_cert_timestamps = - SSL_PeerSignedCertTimestamps(nss_fd_); - - if (!signed_cert_timestamps || !signed_cert_timestamps->len) - return; - - nss_handshake_state_.sct_list_from_tls_extension = std::string( - reinterpret_cast<char*>(signed_cert_timestamps->data), - signed_cert_timestamps->len); -} - -void SSLClientSocketNSS::Core::UpdateStapledOCSPResponse() { - PRBool ocsp_requested = PR_FALSE; - SSL_OptionGet(nss_fd_, SSL_ENABLE_OCSP_STAPLING, &ocsp_requested); - const SECItemArray* ocsp_responses = - SSL_PeerStapledOCSPResponses(nss_fd_); - bool ocsp_responses_present = ocsp_responses && ocsp_responses->len; - if (ocsp_requested) - UMA_HISTOGRAM_BOOLEAN("Net.OCSPResponseStapled", ocsp_responses_present); - if (!ocsp_responses_present) - return; - - nss_handshake_state_.stapled_ocsp_response = std::string( - reinterpret_cast<char*>(ocsp_responses->items[0].data), - ocsp_responses->items[0].len); -} - -void SSLClientSocketNSS::Core::UpdateConnectionStatus() { - // Note: This function may be called multiple times for a single connection - // if renegotiations occur. - nss_handshake_state_.ssl_connection_status = 0; - - SSLChannelInfo channel_info; - SECStatus ok = SSL_GetChannelInfo(nss_fd_, - &channel_info, sizeof(channel_info)); - if (ok == SECSuccess && - channel_info.length == sizeof(channel_info) && - channel_info.cipherSuite) { - nss_handshake_state_.ssl_connection_status |= channel_info.cipherSuite; - - nss_handshake_state_.ssl_connection_status |= - (static_cast<int>(channel_info.compressionMethod) & - SSL_CONNECTION_COMPRESSION_MASK) << - SSL_CONNECTION_COMPRESSION_SHIFT; - - int version = SSL_CONNECTION_VERSION_UNKNOWN; - if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_0) { - version = SSL_CONNECTION_VERSION_TLS1; - } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_1) { - version = SSL_CONNECTION_VERSION_TLS1_1; - } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_2) { - version = SSL_CONNECTION_VERSION_TLS1_2; - } - DCHECK_NE(SSL_CONNECTION_VERSION_UNKNOWN, version); - nss_handshake_state_.ssl_connection_status |= - (version & SSL_CONNECTION_VERSION_MASK) << - SSL_CONNECTION_VERSION_SHIFT; - } - - PRBool peer_supports_renego_ext; - ok = SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn, - &peer_supports_renego_ext); - if (ok == SECSuccess) { - if (!peer_supports_renego_ext) { - nss_handshake_state_.ssl_connection_status |= - SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION; - // Log an informational message if the server does not support secure - // renegotiation (RFC 5746). - VLOG(1) << "The server " << host_and_port_.ToString() - << " does not support the TLS renegotiation_info extension."; - } - } - - if (ssl_config_.version_fallback) { - nss_handshake_state_.ssl_connection_status |= - SSL_CONNECTION_VERSION_FALLBACK; - } -} - -void SSLClientSocketNSS::Core::UpdateNextProto() { - uint8_t buf[256]; - SSLNextProtoState state; - unsigned buf_len; - - SECStatus rv = SSL_GetNextProto(nss_fd_, &state, buf, &buf_len, sizeof(buf)); - if (rv != SECSuccess) - return; - - nss_handshake_state_.next_proto = - std::string(reinterpret_cast<char*>(buf), buf_len); - switch (state) { - case SSL_NEXT_PROTO_NEGOTIATED: - case SSL_NEXT_PROTO_SELECTED: - nss_handshake_state_.next_proto_status = kNextProtoNegotiated; - break; - case SSL_NEXT_PROTO_NO_OVERLAP: - nss_handshake_state_.next_proto_status = kNextProtoNoOverlap; - break; - case SSL_NEXT_PROTO_NO_SUPPORT: - nss_handshake_state_.next_proto_status = kNextProtoUnsupported; - break; - default: - NOTREACHED(); - break; - } -} - -void SSLClientSocketNSS::Core::UpdateExtensionUsed() { - PRBool negotiated_extension; - SECStatus rv = SSL_HandshakeNegotiatedExtension(nss_fd_, - ssl_app_layer_protocol_xtn, - &negotiated_extension); - if (rv == SECSuccess && negotiated_extension) { - nss_handshake_state_.negotiation_extension_ = kExtensionALPN; - } else { - rv = SSL_HandshakeNegotiatedExtension(nss_fd_, - ssl_next_proto_nego_xtn, - &negotiated_extension); - if (rv == SECSuccess && negotiated_extension) { - nss_handshake_state_.negotiation_extension_ = kExtensionNPN; - } - } -} - -bool SSLClientSocketNSS::Core::IsRenegotiationAllowed() const { - DCHECK(OnNSSTaskRunner()); - - if (nss_handshake_state_.next_proto_status == kNextProtoUnsupported) - return ssl_config_.renego_allowed_default; - - NextProto next_proto = NextProtoFromString(nss_handshake_state_.next_proto); - for (NextProto allowed : ssl_config_.renego_allowed_for_protos) { - if (next_proto == allowed) - return true; - } - return false; -} - -void SSLClientSocketNSS::Core::RecordChannelIDSupportOnNSSTaskRunner() { - DCHECK(OnNSSTaskRunner()); - if (nss_handshake_state_.resumed_handshake) - return; - - // Copy the NSS task runner-only state to the network task runner and - // log histograms from there, since the histograms also need access to the - // network task runner state. - PostOrRunCallback( - FROM_HERE, - base::Bind(&Core::RecordChannelIDSupportOnNetworkTaskRunner, this, - channel_id_xtn_negotiated_, ssl_config_.channel_id_enabled)); -} - -void SSLClientSocketNSS::Core::RecordChannelIDSupportOnNetworkTaskRunner( - bool negotiated_channel_id, - bool channel_id_enabled) const { - DCHECK(OnNetworkTaskRunner()); - - RecordChannelIDSupport(channel_id_service_, negotiated_channel_id, - channel_id_enabled); -} - -int SSLClientSocketNSS::Core::DoBufferRecv(IOBuffer* read_buffer, int len) { - DCHECK(OnNetworkTaskRunner()); - DCHECK_GT(len, 0); - - if (detached_) - return ERR_ABORTED; - - int rv = transport_->socket()->Read( - read_buffer, len, - base::Bind(&Core::BufferRecvComplete, base::Unretained(this), - base::RetainedRef(read_buffer))); - - if (!OnNSSTaskRunner() && rv != ERR_IO_PENDING) { - nss_task_runner_->PostTask(FROM_HERE, - base::Bind(&Core::BufferRecvComplete, this, - base::RetainedRef(read_buffer), rv)); - return rv; - } - - return rv; -} - -int SSLClientSocketNSS::Core::DoBufferSend(IOBuffer* send_buffer, int len) { - DCHECK(OnNetworkTaskRunner()); - DCHECK_GT(len, 0); - - if (detached_) - return ERR_ABORTED; - - int rv = transport_->socket()->Write( - send_buffer, len, - base::Bind(&Core::BufferSendComplete, - base::Unretained(this))); - - if (!OnNSSTaskRunner() && rv != ERR_IO_PENDING) { - nss_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Core::BufferSendComplete, this, rv)); - return rv; - } - - return rv; -} - -int SSLClientSocketNSS::Core::DoGetChannelID(const std::string& host) { - DCHECK(OnNetworkTaskRunner()); - - if (detached_) - return ERR_ABORTED; - - weak_net_log_->BeginEvent(NetLog::TYPE_SSL_GET_DOMAIN_BOUND_CERT); - - int rv = channel_id_service_->GetOrCreateChannelID( - host, &channel_id_key_, - base::Bind(&Core::OnGetChannelIDComplete, base::Unretained(this)), - &channel_id_request_); - - if (rv != ERR_IO_PENDING && !OnNSSTaskRunner()) { - nss_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Core::OnHandshakeIOComplete, this, rv)); - return ERR_IO_PENDING; - } - - return rv; -} - -void SSLClientSocketNSS::Core::OnHandshakeStateUpdated( - const HandshakeState& state) { - DCHECK(OnNetworkTaskRunner()); - network_handshake_state_ = state; -} - -void SSLClientSocketNSS::Core::OnNSSBufferUpdated(int amount_in_read_buffer) { - DCHECK(OnNetworkTaskRunner()); - unhandled_buffer_size_ = amount_in_read_buffer; -} - -void SSLClientSocketNSS::Core::DidNSSRead(int result) { - DCHECK(OnNetworkTaskRunner()); - DCHECK(nss_waiting_read_); - nss_waiting_read_ = false; - if (result <= 0) { - nss_is_closed_ = true; - } else { - was_ever_used_ = true; - } -} - -void SSLClientSocketNSS::Core::DidNSSWrite(int result) { - DCHECK(OnNetworkTaskRunner()); - DCHECK(nss_waiting_write_); - nss_waiting_write_ = false; - if (result < 0) { - nss_is_closed_ = true; - } else if (result > 0) { - was_ever_used_ = true; - } -} - -void SSLClientSocketNSS::Core::BufferSendComplete(int result) { - if (!OnNSSTaskRunner()) { - if (detached_) - return; - - nss_task_runner_->PostTask( - FROM_HERE, base::Bind(&Core::BufferSendComplete, this, result)); - return; - } - - DCHECK(OnNSSTaskRunner()); - - memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result)); - transport_send_busy_ = false; - OnSendComplete(result); -} - -void SSLClientSocketNSS::Core::OnHandshakeIOComplete(int result) { - if (!OnNSSTaskRunner()) { - if (detached_) - return; - - nss_task_runner_->PostTask( - FROM_HERE, base::Bind(&Core::OnHandshakeIOComplete, this, result)); - return; - } - - DCHECK(OnNSSTaskRunner()); - - int rv = DoHandshakeLoop(result); - if (rv != ERR_IO_PENDING) - DoConnectCallback(rv); -} - -void SSLClientSocketNSS::Core::OnGetChannelIDComplete(int result) { - DVLOG(1) << __FUNCTION__ << " " << result; - DCHECK(OnNetworkTaskRunner()); - - OnHandshakeIOComplete(result); -} - -void SSLClientSocketNSS::Core::BufferRecvComplete( - IOBuffer* read_buffer, - int result) { - DCHECK(read_buffer); - - if (!OnNSSTaskRunner()) { - if (detached_) - return; - - nss_task_runner_->PostTask( - FROM_HERE, base::Bind(&Core::BufferRecvComplete, this, - base::RetainedRef(read_buffer), result)); - return; - } - - DCHECK(OnNSSTaskRunner()); - - if (result > 0) { - char* buf; - int nb = memio_GetReadParams(nss_bufs_, &buf); - CHECK_GE(nb, result); - memcpy(buf, read_buffer->data(), result); - } else if (result == 0) { - transport_recv_eof_ = true; - } - - memio_PutReadResult(nss_bufs_, MapErrorToNSS(result)); - transport_recv_busy_ = false; - OnRecvComplete(result); -} - -void SSLClientSocketNSS::Core::PostOrRunCallback( - const tracked_objects::Location& location, - const base::Closure& task) { - if (!OnNetworkTaskRunner()) { - network_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Core::PostOrRunCallback, this, location, task)); - return; - } - - if (detached_ || task.is_null()) - return; - task.Run(); -} - -void SSLClientSocketNSS::Core::AddCertProvidedEvent(int cert_count) { - PostOrRunCallback(FROM_HERE, - base::Bind(&AddLogEventWithCallback, weak_net_log_, - NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED, - NetLog::IntCallback("cert_count", cert_count))); -} - -void SSLClientSocketNSS::Core::SetChannelIDProvided() { - PostOrRunCallback( - FROM_HERE, base::Bind(&AddLogEvent, weak_net_log_, - NetLog::TYPE_SSL_CHANNEL_ID_PROVIDED)); - nss_handshake_state_.channel_id_sent = true; - // Update the network task runner's view of the handshake state now that - // channel id has been sent. - PostOrRunCallback( - FROM_HERE, base::Bind(&Core::OnHandshakeStateUpdated, this, - nss_handshake_state_)); -} - -SSLClientSocketNSS::SSLClientSocketNSS( - std::unique_ptr<ClientSocketHandle> transport_socket, - const HostPortPair& host_and_port, - const SSLConfig& ssl_config, - const SSLClientSocketContext& context) - : transport_(std::move(transport_socket)), - host_and_port_(host_and_port), - ssl_config_(ssl_config), - cert_verifier_(context.cert_verifier), - cert_transparency_verifier_(context.cert_transparency_verifier), - channel_id_service_(context.channel_id_service), - ssl_session_cache_shard_(context.ssl_session_cache_shard), - completed_handshake_(false), - next_handshake_state_(STATE_NONE), - disconnected_(false), - nss_fd_(NULL), - net_log_(transport_->socket()->NetLog()), - transport_security_state_(context.transport_security_state), - policy_enforcer_(context.ct_policy_enforcer), - valid_thread_id_(base::kInvalidThreadId) { - DCHECK(cert_verifier_); - - EnterFunction(""); - InitCore(); - LeaveFunction(""); -} - -SSLClientSocketNSS::~SSLClientSocketNSS() { - EnterFunction(""); - Disconnect(); - LeaveFunction(""); -} - -// static -void SSLClientSocket::ClearSessionCache() { - // SSL_ClearSessionCache can't be called before NSS is initialized. Don't - // bother initializing NSS just to clear an empty SSL session cache. - if (!NSS_IsInitialized()) - return; - - SSL_ClearSessionCache(); -} - -bool SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { - EnterFunction(""); - ssl_info->Reset(); - if (core_->state().server_cert_chain.empty() || - !core_->state().server_cert_chain[0]) { - return false; - } - - ssl_info->cert_status = server_cert_verify_result_.cert_status; - ssl_info->cert = server_cert_verify_result_.verified_cert; - ssl_info->unverified_cert = core_->state().server_cert; - - AddCTInfoToSSLInfo(ssl_info); - - ssl_info->connection_status = - core_->state().ssl_connection_status; - ssl_info->public_key_hashes = server_cert_verify_result_.public_key_hashes; - ssl_info->is_issued_by_known_root = - server_cert_verify_result_.is_issued_by_known_root; - ssl_info->client_cert_sent = - ssl_config_.send_client_cert && ssl_config_.client_cert.get(); - ssl_info->channel_id_sent = core_->state().channel_id_sent; - ssl_info->pinning_failure_log = pinning_failure_log_; - - PRUint16 cipher_suite = SSLConnectionStatusToCipherSuite( - core_->state().ssl_connection_status); - SSLCipherSuiteInfo cipher_info; - SECStatus ok = SSL_GetCipherSuiteInfo(cipher_suite, - &cipher_info, sizeof(cipher_info)); - if (ok == SECSuccess) { - ssl_info->security_bits = cipher_info.effectiveKeyBits; - } else { - ssl_info->security_bits = -1; - LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError() - << " for cipherSuite " << cipher_suite; - } - - ssl_info->handshake_type = core_->state().resumed_handshake ? - SSLInfo::HANDSHAKE_RESUME : SSLInfo::HANDSHAKE_FULL; - - LeaveFunction(""); - return true; -} - -void SSLClientSocketNSS::GetConnectionAttempts(ConnectionAttempts* out) const { - out->clear(); -} - -int64_t SSLClientSocketNSS::GetTotalReceivedBytes() const { - NOTIMPLEMENTED(); - return 0; -} - -void SSLClientSocketNSS::GetSSLCertRequestInfo( - SSLCertRequestInfo* cert_request_info) { - EnterFunction(""); - cert_request_info->host_and_port = host_and_port_; - cert_request_info->cert_authorities = core_->state().cert_authorities; - LeaveFunction(""); -} - -int SSLClientSocketNSS::ExportKeyingMaterial(const base::StringPiece& label, - bool has_context, - const base::StringPiece& context, - unsigned char* out, - unsigned int outlen) { - if (!IsConnected()) - return ERR_SOCKET_NOT_CONNECTED; - - // SSL_ExportKeyingMaterial may block the current thread if |core_| is in - // the midst of a handshake. - SECStatus result = SSL_ExportKeyingMaterial( - nss_fd_, label.data(), label.size(), has_context, - reinterpret_cast<const unsigned char*>(context.data()), - context.length(), out, outlen); - if (result != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_ExportKeyingMaterial", ""); - return MapNSSError(PORT_GetError()); - } - return OK; -} - -SSLClientSocket::NextProtoStatus SSLClientSocketNSS::GetNextProto( - std::string* proto) const { - *proto = core_->state().next_proto; - return core_->state().next_proto_status; -} - -int SSLClientSocketNSS::Connect(const CompletionCallback& callback) { - EnterFunction(""); - DCHECK(transport_.get()); - // It is an error to create an SSLClientSocket whose context has no - // TransportSecurityState. - DCHECK(transport_security_state_); - DCHECK_EQ(STATE_NONE, next_handshake_state_); - DCHECK(user_connect_callback_.is_null()); - DCHECK(!callback.is_null()); - - // Although StreamSocket does allow calling Connect() after Disconnect(), - // this has never worked for layered sockets. CHECK to detect any consumers - // reconnecting an SSL socket. - // - // TODO(davidben,mmenke): Remove this API feature. See - // https://crbug.com/499289. - CHECK(!disconnected_); - - EnsureThreadIdAssigned(); - - net_log_.BeginEvent(NetLog::TYPE_SSL_CONNECT); - - int rv = Init(); - if (rv != OK) { - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); - return rv; - } - - rv = InitializeSSLOptions(); - if (rv != OK) { - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); - return rv; - } - - rv = InitializeSSLPeerName(); - if (rv != OK) { - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); - return rv; - } - - GotoState(STATE_HANDSHAKE); - - rv = DoHandshakeLoop(OK); - if (rv == ERR_IO_PENDING) { - user_connect_callback_ = callback; - } else { - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); - } - - LeaveFunction(""); - return rv > OK ? OK : rv; -} - -void SSLClientSocketNSS::Disconnect() { - EnterFunction(""); - - CHECK(CalledOnValidThread()); - - // Shut down anything that may call us back. - core_->Detach(); - cert_verifier_request_.reset(); - transport_->socket()->Disconnect(); - - disconnected_ = true; - - // Reset object state. - user_connect_callback_.Reset(); - server_cert_verify_result_.Reset(); - completed_handshake_ = false; - start_cert_verification_time_ = base::TimeTicks(); - InitCore(); - - LeaveFunction(""); -} - -bool SSLClientSocketNSS::IsConnected() const { - EnterFunction(""); - bool ret = completed_handshake_ && - (core_->HasPendingAsyncOperation() || - (core_->IsConnected() && core_->HasUnhandledReceivedData()) || - transport_->socket()->IsConnected()); - LeaveFunction(""); - return ret; -} - -bool SSLClientSocketNSS::IsConnectedAndIdle() const { - EnterFunction(""); - bool ret = completed_handshake_ && - !core_->HasPendingAsyncOperation() && - !(core_->IsConnected() && core_->HasUnhandledReceivedData()) && - transport_->socket()->IsConnectedAndIdle(); - LeaveFunction(""); - return ret; -} - -int SSLClientSocketNSS::GetPeerAddress(IPEndPoint* address) const { - return transport_->socket()->GetPeerAddress(address); -} - -int SSLClientSocketNSS::GetLocalAddress(IPEndPoint* address) const { - return transport_->socket()->GetLocalAddress(address); -} - -const BoundNetLog& SSLClientSocketNSS::NetLog() const { - return net_log_; -} - -void SSLClientSocketNSS::SetSubresourceSpeculation() { - if (transport_.get() && transport_->socket()) { - transport_->socket()->SetSubresourceSpeculation(); - } else { - NOTREACHED(); - } -} - -void SSLClientSocketNSS::SetOmniboxSpeculation() { - if (transport_.get() && transport_->socket()) { - transport_->socket()->SetOmniboxSpeculation(); - } else { - NOTREACHED(); - } -} - -bool SSLClientSocketNSS::WasEverUsed() const { - DCHECK(core_.get()); - - return core_->WasEverUsed(); -} - -int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { - DCHECK(core_.get()); - DCHECK(!callback.is_null()); - - EnterFunction(buf_len); - int rv = core_->Read(buf, buf_len, callback); - LeaveFunction(rv); - - return rv; -} - -int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { - DCHECK(core_.get()); - DCHECK(!callback.is_null()); - - EnterFunction(buf_len); - int rv = core_->Write(buf, buf_len, callback); - LeaveFunction(rv); - - return rv; -} - -int SSLClientSocketNSS::SetReceiveBufferSize(int32_t size) { - return transport_->socket()->SetReceiveBufferSize(size); -} - -int SSLClientSocketNSS::SetSendBufferSize(int32_t size) { - return transport_->socket()->SetSendBufferSize(size); -} - -int SSLClientSocketNSS::Init() { - EnterFunction(""); - // Initialize the NSS SSL library in a threadsafe way. This also - // initializes the NSS base library. - EnsureNSSSSLInit(); - if (!NSS_IsInitialized()) - return ERR_UNEXPECTED; -#if defined(USE_NSS_VERIFIER) - if (ssl_config_.cert_io_enabled) { - // We must call EnsureNSSHttpIOInit() here, on the IO thread, to get the IO - // loop by MessageLoopForIO::current(). - // X509Certificate::Verify() runs on a worker thread of CertVerifier. - EnsureNSSHttpIOInit(); - } -#endif - - LeaveFunction(""); - return OK; -} - -void SSLClientSocketNSS::InitCore() { - // TODO(davidben): Both task runners are now always the same. Unwind this code - // further, although the entire class is due to be deleted eventually, so it - // may not be worth bothering. - core_ = new Core(base::ThreadTaskRunnerHandle::Get().get(), - base::ThreadTaskRunnerHandle::Get().get(), transport_.get(), - host_and_port_, ssl_config_, &net_log_, channel_id_service_); -} - -int SSLClientSocketNSS::InitializeSSLOptions() { - // Transport connected, now hook it up to nss - nss_fd_ = memio_CreateIOLayer(kRecvBufferSize, kSendBufferSize); - if (nss_fd_ == NULL) { - return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR error code. - } - - // Grab pointer to buffers - memio_Private* nss_bufs = memio_GetSecret(nss_fd_); - - /* Create SSL state machine */ - /* Push SSL onto our fake I/O socket */ - if (SSL_ImportFD(GetNSSModelSocket(), nss_fd_) == NULL) { - LogFailedNSSFunction(net_log_, "SSL_ImportFD", ""); - PR_Close(nss_fd_); - nss_fd_ = NULL; - return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR/NSS error code. - } - // TODO(port): set more ssl options! Check errors! - - int rv; - - rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_SECURITY"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL2"); - return ERR_UNEXPECTED; - } - - // Don't do V2 compatible hellos because they don't support TLS extensions. - rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_V2_COMPATIBLE_HELLO"); - return ERR_UNEXPECTED; - } - - SSLVersionRange version_range; - version_range.min = ssl_config_.version_min; - version_range.max = ssl_config_.version_max; - rv = SSL_VersionRangeSet(nss_fd_, &version_range); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_VersionRangeSet", ""); - return ERR_NO_SSL_VERSIONS_ENABLED; - } - - if (ssl_config_.require_ecdhe) { - const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers(); - const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers(); - - // Iterate over the cipher suites and disable those that don't use ECDHE. - for (unsigned i = 0; i < num_ciphers; i++) { - SSLCipherSuiteInfo info; - if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) == - SECSuccess) { - if (strcmp(info.keaTypeName, "ECDHE") != 0) { - SSL_CipherPrefSet(nss_fd_, ssl_ciphers[i], PR_FALSE); - } - } - } - } - - if (ssl_config_.version_fallback) { - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction( - net_log_, "SSL_OptionSet", "SSL_ENABLE_FALLBACK_SCSV"); - } - } - - for (std::vector<uint16_t>::const_iterator it = - ssl_config_.disabled_cipher_suites.begin(); - it != ssl_config_.disabled_cipher_suites.end(); ++it) { - // This will fail if the specified cipher is not implemented by NSS, but - // the failure is harmless. - SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE); - } - - const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers(); - const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers(); - for (int i = 0; i < num_ciphers; i++) { - SSLCipherSuiteInfo info; - if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) != - SECSuccess) { - continue; - } - if (info.symCipher == ssl_calg_rc4 && - !(ssl_config_.rc4_enabled && - ssl_config_.deprecated_cipher_suites_enabled)) { - SSL_CipherPrefSet(nss_fd_, ssl_ciphers[i], PR_FALSE); - } - if (info.keaType == ssl_kea_dh && - !ssl_config_.deprecated_cipher_suites_enabled) { - // Only offer DHE on the second handshake. https://crbug.com/538690 - SSL_CipherPrefSet(nss_fd_, ssl_ciphers[i], PR_FALSE); - } - } - - // Support RFC 5077 - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction( - net_log_, "SSL_OptionSet", "SSL_ENABLE_SESSION_TICKETS"); - } - - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_FALSE_START, - ssl_config_.false_start_enabled); - if (rv != SECSuccess) - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_FALSE_START"); - - // By default, renegotiations are rejected. After the initial handshake - // completes, some application protocols may re-enable it. - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER); - if (rv != SECSuccess) { - LogFailedNSSFunction( - net_log_, "SSL_OptionSet", "SSL_ENABLE_RENEGOTIATION"); - } - - rv = SSL_OptionSet(nss_fd_, SSL_CBC_RANDOM_IV, PR_TRUE); - if (rv != SECSuccess) - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_CBC_RANDOM_IV"); - -// Added in NSS 3.15 -#ifdef SSL_ENABLE_OCSP_STAPLING - // Request OCSP stapling even on platforms that don't support it, in - // order to extract Certificate Transparency information. - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_OCSP_STAPLING, - cert_verifier_->SupportsOCSPStapling() || - ssl_config_.signed_cert_timestamps_enabled); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", - "SSL_ENABLE_OCSP_STAPLING"); - } -#endif - - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, - ssl_config_.signed_cert_timestamps_enabled); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", - "SSL_ENABLE_SIGNED_CERT_TIMESTAMPS"); - } - - rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_CLIENT"); - return ERR_UNEXPECTED; - } - - if (!core_->Init(nss_fd_, nss_bufs)) - return ERR_UNEXPECTED; - - // Tell SSL the hostname we're trying to connect to. - SSL_SetURL(nss_fd_, host_and_port_.host().c_str()); - - // Tell SSL we're a client; needed if not letting NSPR do socket I/O - SSL_ResetHandshake(nss_fd_, PR_FALSE); - - return OK; -} - -int SSLClientSocketNSS::InitializeSSLPeerName() { - // Tell NSS who we're connected to - IPEndPoint peer_address; - int err = transport_->socket()->GetPeerAddress(&peer_address); - if (err != OK) - return err; - - SockaddrStorage storage; - if (!peer_address.ToSockAddr(storage.addr, &storage.addr_len)) - return ERR_ADDRESS_INVALID; - - PRNetAddr peername; - memset(&peername, 0, sizeof(peername)); - DCHECK_LE(static_cast<size_t>(storage.addr_len), sizeof(peername)); - size_t len = std::min(static_cast<size_t>(storage.addr_len), - sizeof(peername)); - memcpy(&peername, storage.addr, len); - - // Adjust the address family field for BSD, whose sockaddr - // structure has a one-byte length and one-byte address family - // field at the beginning. PRNetAddr has a two-byte address - // family field at the beginning. - peername.raw.family = storage.addr->sa_family; - - memio_SetPeerName(nss_fd_, &peername); - - // Set the peer ID for session reuse. This is necessary when we create an - // SSL tunnel through a proxy -- GetPeerName returns the proxy's address - // rather than the destination server's address in that case. - std::string peer_id = host_and_port_.ToString(); - // Append |ssl_session_cache_shard_| to the peer id. This is used to partition - // the session cache for incognito mode. - peer_id += "/" + ssl_session_cache_shard_; - peer_id += "/"; - // Shard the session cache based on maximum protocol version. This causes - // fallback connections to use a separate session cache. - switch (ssl_config_.version_max) { - case SSL_PROTOCOL_VERSION_TLS1: - peer_id += "tls1"; - break; - case SSL_PROTOCOL_VERSION_TLS1_1: - peer_id += "tls1.1"; - break; - case SSL_PROTOCOL_VERSION_TLS1_2: - peer_id += "tls1.2"; - break; - default: - NOTREACHED(); - } - peer_id += "/"; - if (ssl_config_.deprecated_cipher_suites_enabled) - peer_id += "deprecated"; - - peer_id += "/"; - if (ssl_config_.channel_id_enabled) - peer_id += "channelid"; - - SECStatus rv = SSL_SetSockPeerID(nss_fd_, const_cast<char*>(peer_id.c_str())); - if (rv != SECSuccess) - LogFailedNSSFunction(net_log_, "SSL_SetSockPeerID", peer_id.c_str()); - - return OK; -} - -void SSLClientSocketNSS::DoConnectCallback(int rv) { - EnterFunction(rv); - DCHECK_NE(ERR_IO_PENDING, rv); - DCHECK(!user_connect_callback_.is_null()); - - base::ResetAndReturn(&user_connect_callback_).Run(rv > OK ? OK : rv); - LeaveFunction(""); -} - -void SSLClientSocketNSS::OnHandshakeIOComplete(int result) { - EnterFunction(result); - int rv = DoHandshakeLoop(result); - if (rv != ERR_IO_PENDING) { - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv); - DoConnectCallback(rv); - } - LeaveFunction(""); -} - -int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) { - EnterFunction(last_io_result); - int rv = last_io_result; - do { - // Default to STATE_NONE for next state. - // (This is a quirk carried over from the windows - // implementation. It makes reading the logs a bit harder.) - // State handlers can and often do call GotoState just - // to stay in the current state. - State state = next_handshake_state_; - GotoState(STATE_NONE); - switch (state) { - case STATE_HANDSHAKE: - rv = DoHandshake(); - break; - case STATE_HANDSHAKE_COMPLETE: - rv = DoHandshakeComplete(rv); - break; - case STATE_VERIFY_CERT: - DCHECK(rv == OK); - rv = DoVerifyCert(rv); - break; - case STATE_VERIFY_CERT_COMPLETE: - rv = DoVerifyCertComplete(rv); - break; - case STATE_NONE: - default: - rv = ERR_UNEXPECTED; - LOG(DFATAL) << "unexpected state " << state; - break; - } - } while (rv != ERR_IO_PENDING && next_handshake_state_ != STATE_NONE); - LeaveFunction(""); - return rv; -} - -int SSLClientSocketNSS::DoHandshake() { - EnterFunction(""); - - int rv = core_->Connect( - base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete, - base::Unretained(this))); - GotoState(STATE_HANDSHAKE_COMPLETE); - - LeaveFunction(rv); - return rv; -} - -int SSLClientSocketNSS::DoHandshakeComplete(int result) { - EnterFunction(result); - - if (result == OK) { - if (ssl_config_.version_fallback && - ssl_config_.version_max < ssl_config_.version_fallback_min) { - return ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION; - } - - RecordNegotiationExtension(); - - // SSL handshake is completed. Let's verify the certificate. - GotoState(STATE_VERIFY_CERT); - // Done! - } - set_signed_cert_timestamps_received( - !core_->state().sct_list_from_tls_extension.empty()); - set_stapled_ocsp_response_received( - !core_->state().stapled_ocsp_response.empty()); - set_negotiation_extension(core_->state().negotiation_extension_); - - LeaveFunction(result); - return result; -} - -int SSLClientSocketNSS::DoVerifyCert(int result) { - DCHECK(!core_->state().server_cert_chain.empty()); - DCHECK(core_->state().server_cert_chain[0]); - - GotoState(STATE_VERIFY_CERT_COMPLETE); - - // NSS decoded the certificate, but the platform certificate implementation - // could not. This is treated as a fatal SSL-level protocol error rather than - // a certificate error. See https://crbug.com/91341. - if (!core_->state().server_cert.get()) - return ERR_SSL_SERVER_CERT_BAD_FORMAT; - - // If the certificate is expected to be bad we can use the expectation as - // the cert status. - base::StringPiece der_cert( - reinterpret_cast<char*>( - core_->state().server_cert_chain[0]->derCert.data), - core_->state().server_cert_chain[0]->derCert.len); - CertStatus cert_status; - if (ssl_config_.IsAllowedBadCert(der_cert, &cert_status)) { - DCHECK(start_cert_verification_time_.is_null()); - VLOG(1) << "Received an expected bad cert with status: " << cert_status; - server_cert_verify_result_.Reset(); - server_cert_verify_result_.cert_status = cert_status; - server_cert_verify_result_.verified_cert = core_->state().server_cert; - return OK; - } - - start_cert_verification_time_ = base::TimeTicks::Now(); - - return cert_verifier_->Verify( - core_->state().server_cert.get(), host_and_port_.host(), - core_->state().stapled_ocsp_response, ssl_config_.GetCertVerifyFlags(), - SSLConfigService::GetCRLSet().get(), &server_cert_verify_result_, - base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete, - base::Unretained(this)), - &cert_verifier_request_, net_log_); -} - -// Derived from AuthCertificateCallback() in -// mozilla/source/security/manager/ssl/src/nsNSSCallbacks.cpp. -int SSLClientSocketNSS::DoVerifyCertComplete(int result) { - cert_verifier_request_.reset(); - - if (!start_cert_verification_time_.is_null()) { - base::TimeDelta verify_time = - base::TimeTicks::Now() - start_cert_verification_time_; - if (result == OK) - UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTime", verify_time); - else - UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTimeError", verify_time); - } - - // We used to remember the intermediate CA certs in the NSS database - // persistently. However, NSS opens a connection to the SQLite database - // during NSS initialization and doesn't close the connection until NSS - // shuts down. If the file system where the database resides is gone, - // the database connection goes bad. What's worse, the connection won't - // recover when the file system comes back. Until this NSS or SQLite bug - // is fixed, we need to avoid using the NSS database for non-essential - // purposes. See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and - // http://crbug.com/15630 for more info. - - const CertStatus cert_status = server_cert_verify_result_.cert_status; - if (transport_security_state_ && - (result == OK || - (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) && - !transport_security_state_->CheckPublicKeyPins( - host_and_port_, server_cert_verify_result_.is_issued_by_known_root, - server_cert_verify_result_.public_key_hashes, - core_->state().server_cert.get(), - server_cert_verify_result_.verified_cert.get(), - TransportSecurityState::ENABLE_PIN_REPORTS, &pinning_failure_log_)) { - result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN; - } - - if (result == OK) { - // Only check Certificate Transparency if there were no other errors with - // the connection. - VerifyCT(); - - // Only cache the session if the certificate verified successfully. - core_->CacheSessionIfNecessary(); - } - - completed_handshake_ = true; - - // Exit DoHandshakeLoop and return the result to the caller to Connect. - DCHECK_EQ(STATE_NONE, next_handshake_state_); - return result; -} - -void SSLClientSocketNSS::VerifyCT() { - if (!cert_transparency_verifier_) - return; - - // Note that this is a completely synchronous operation: The CT Log Verifier - // gets all the data it needs for SCT verification and does not do any - // external communication. - cert_transparency_verifier_->Verify( - server_cert_verify_result_.verified_cert.get(), - core_->state().stapled_ocsp_response, - core_->state().sct_list_from_tls_extension, &ct_verify_result_, net_log_); - // TODO(ekasper): wipe stapled_ocsp_response and sct_list_from_tls_extension - // from the state after verification is complete, to conserve memory. - - ct_verify_result_.ct_policies_applied = (policy_enforcer_ != nullptr); - ct_verify_result_.ev_policy_compliance = - ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; - if (policy_enforcer_) { - if ((server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV)) { - scoped_refptr<ct::EVCertsWhitelist> ev_whitelist = - SSLConfigService::GetEVCertsWhitelist(); - ct::EVPolicyCompliance ev_policy_compliance = - policy_enforcer_->DoesConformToCTEVPolicy( - server_cert_verify_result_.verified_cert.get(), - ev_whitelist.get(), ct_verify_result_.verified_scts, net_log_); - ct_verify_result_.ev_policy_compliance = ev_policy_compliance; - if (ev_policy_compliance != - ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY && - ev_policy_compliance != - ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST && - ev_policy_compliance != - ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS) { - // TODO(eranm): Log via the BoundNetLog, see crbug.com/437766 - VLOG(1) << "EV certificate for " - << server_cert_verify_result_.verified_cert->subject() - .GetDisplayName() - << " does not conform to CT policy, removing EV status."; - server_cert_verify_result_.cert_status |= - CERT_STATUS_CT_COMPLIANCE_FAILED; - server_cert_verify_result_.cert_status &= ~CERT_STATUS_IS_EV; - } - } - ct_verify_result_.cert_policy_compliance = - policy_enforcer_->DoesConformToCertPolicy( - server_cert_verify_result_.verified_cert.get(), - ct_verify_result_.verified_scts, net_log_); - } -} - -void SSLClientSocketNSS::EnsureThreadIdAssigned() const { - base::AutoLock auto_lock(lock_); - if (valid_thread_id_ != base::kInvalidThreadId) - return; - valid_thread_id_ = base::PlatformThread::CurrentId(); -} - -bool SSLClientSocketNSS::CalledOnValidThread() const { - EnsureThreadIdAssigned(); - base::AutoLock auto_lock(lock_); - return valid_thread_id_ == base::PlatformThread::CurrentId(); -} - -void SSLClientSocketNSS::AddCTInfoToSSLInfo(SSLInfo* ssl_info) const { - ssl_info->UpdateCertificateTransparencyInfo(ct_verify_result_); -} - -// static -void SSLClientSocketNSS::ReorderNextProtos(NextProtoVector* next_protos) { - if (next_protos->size() < 2) { - return; - } - - NextProto fallback_proto = next_protos->back(); - for (size_t i = next_protos->size() - 1; i > 0; --i) { - (*next_protos)[i] = (*next_protos)[i - 1]; - } - (*next_protos)[0] = fallback_proto; -} - -ChannelIDService* SSLClientSocketNSS::GetChannelIDService() const { - return channel_id_service_; -} - -Error SSLClientSocketNSS::GetSignedEKMForTokenBinding( - crypto::ECPrivateKey* key, - std::vector<uint8_t>* out) { - NOTREACHED(); - return ERR_NOT_IMPLEMENTED; -} - -crypto::ECPrivateKey* SSLClientSocketNSS::GetChannelIDKey() const { - return core_->GetChannelIDKey(); -} - -SSLFailureState SSLClientSocketNSS::GetSSLFailureState() const { - if (completed_handshake_) - return SSL_FAILURE_NONE; - return SSL_FAILURE_UNKNOWN; -} - -} // namespace net
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h deleted file mode 100644 index c96fc41..0000000 --- a/net/socket/ssl_client_socket_nss.h +++ /dev/null
@@ -1,218 +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. - -#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_ -#define NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_ - -#include <certt.h> -#include <keyt.h> -#include <nspr.h> -#include <nss.h> -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include "base/synchronization/lock.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "net/base/completion_callback.h" -#include "net/base/host_port_pair.h" -#include "net/base/net_export.h" -#include "net/base/nss_memio.h" -#include "net/cert/cert_verifier.h" -#include "net/cert/cert_verify_result.h" -#include "net/cert/ct_verify_result.h" -#include "net/cert/x509_certificate.h" -#include "net/log/net_log.h" -#include "net/socket/ssl_client_socket.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/ssl_config_service.h" - -namespace net { - -class BoundNetLog; -class CTPolicyEnforcer; -class CertVerifier; -class ChannelIDService; -class CTVerifier; -class ClientSocketHandle; -class TransportSecurityState; -class X509Certificate; - -// An SSL client socket implemented with Mozilla NSS. -class SSLClientSocketNSS : public SSLClientSocket { - public: - // Takes ownership of the |transport_socket|, which must already be connected. - // The hostname specified in |host_and_port| will be compared with the name(s) - // in the server's certificate during the SSL handshake. If SSL client - // authentication is requested, the host_and_port field of SSLCertRequestInfo - // will be populated with |host_and_port|. |ssl_config| specifies - // the SSL settings. - SSLClientSocketNSS(std::unique_ptr<ClientSocketHandle> transport_socket, - const HostPortPair& host_and_port, - const SSLConfig& ssl_config, - const SSLClientSocketContext& context); - ~SSLClientSocketNSS() override; - - // SSLClientSocket implementation. - void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override; - NextProtoStatus GetNextProto(std::string* proto) const override; - - // SSLSocket implementation. - int ExportKeyingMaterial(const base::StringPiece& label, - bool has_context, - const base::StringPiece& context, - unsigned char* out, - unsigned int outlen) override; - - // StreamSocket implementation. - int Connect(const CompletionCallback& callback) override; - void Disconnect() override; - bool IsConnected() const override; - bool IsConnectedAndIdle() const override; - int GetPeerAddress(IPEndPoint* address) const override; - int GetLocalAddress(IPEndPoint* address) const override; - const BoundNetLog& NetLog() const override; - void SetSubresourceSpeculation() override; - void SetOmniboxSpeculation() override; - bool WasEverUsed() const override; - bool GetSSLInfo(SSLInfo* ssl_info) override; - void GetConnectionAttempts(ConnectionAttempts* out) const override; - void ClearConnectionAttempts() override {} - void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} - int64_t GetTotalReceivedBytes() const override; - - // Socket implementation. - int Read(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override; - int Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override; - int SetReceiveBufferSize(int32_t size) override; - int SetSendBufferSize(int32_t size) override; - - // SSLClientSocket implementation. - ChannelIDService* GetChannelIDService() const override; - Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key, - std::vector<uint8_t>* out) override; - crypto::ECPrivateKey* GetChannelIDKey() const override; - SSLFailureState GetSSLFailureState() const override; - - private: - // Helper class to handle marshalling any NSS interaction to and from the - // NSS and network task runners. Not every call needs to happen on the Core - class Core; - - enum State { - STATE_NONE, - STATE_HANDSHAKE, - STATE_HANDSHAKE_COMPLETE, - STATE_VERIFY_CERT, - STATE_VERIFY_CERT_COMPLETE, - }; - - int Init(); - void InitCore(); - - // Initializes NSS SSL options. Returns a net error code. - int InitializeSSLOptions(); - - // Initializes the socket peer name in SSL. Returns a net error code. - int InitializeSSLPeerName(); - - void DoConnectCallback(int result); - void OnHandshakeIOComplete(int result); - - int DoHandshakeLoop(int last_io_result); - int DoHandshake(); - int DoHandshakeComplete(int result); - int DoVerifyCert(int result); - int DoVerifyCertComplete(int result); - - void VerifyCT(); - - // The following methods are for debugging bug 65948. Will remove this code - // after fixing bug 65948. - void EnsureThreadIdAssigned() const; - bool CalledOnValidThread() const; - - // Adds the SignedCertificateTimestamps from ct_verify_result_ to |ssl_info|. - // SCTs are held in three separate vectors in ct_verify_result, each - // vetor representing a particular verification state, this method associates - // each of the SCTs with the corresponding SCTVerifyStatus as it adds it to - // the |ssl_info|.signed_certificate_timestamps list. - void AddCTInfoToSSLInfo(SSLInfo* ssl_info) const; - - // Move last protocol to first place: SSLConfig::next_protos has protocols in - // decreasing order of preference with NPN fallback protocol at the end, but - // NSS moves the first one to the last place before sending them in ALPN, and - // uses the first one as a fallback for NPN. - static void ReorderNextProtos(NextProtoVector* next_protos); - - std::unique_ptr<ClientSocketHandle> transport_; - HostPortPair host_and_port_; - SSLConfig ssl_config_; - - scoped_refptr<Core> core_; - - CompletionCallback user_connect_callback_; - - CertVerifyResult server_cert_verify_result_; - - CertVerifier* const cert_verifier_; - std::unique_ptr<CertVerifier::Request> cert_verifier_request_; - - // Certificate Transparency: Verifier and result holder. - ct::CTVerifyResult ct_verify_result_; - CTVerifier* cert_transparency_verifier_; - - // The service for retrieving Channel ID keys. May be NULL. - ChannelIDService* channel_id_service_; - - // ssl_session_cache_shard_ is an opaque string that partitions the SSL - // session cache. i.e. sessions created with one value will not attempt to - // resume on the socket with a different value. - const std::string ssl_session_cache_shard_; - - // True if the SSL handshake has been completed. - bool completed_handshake_; - - State next_handshake_state_; - - // True if the socket has been disconnected. - bool disconnected_; - - // The NSS SSL state machine. This is owned by |core_|. - // TODO(rsleevi): http://crbug.com/130616 - Remove this member once - // ExportKeyingMaterial is updated to be asynchronous. - PRFileDesc* nss_fd_; - - BoundNetLog net_log_; - - base::TimeTicks start_cert_verification_time_; - - TransportSecurityState* transport_security_state_; - - CTPolicyEnforcer* const policy_enforcer_; - - // pinning_failure_log contains a message produced by - // TransportSecurityState::CheckPublicKeyPins in the event of a - // pinning failure. It is a (somewhat) human-readable string. - std::string pinning_failure_log_; - - // The following two variables are added for debugging bug 65948. Will - // remove this code after fixing bug 65948. - // Added the following code Debugging in release mode. - mutable base::Lock lock_; - // This is mutable so that CalledOnValidThread can set it. - // It's guarded by |lock_|. - mutable base::PlatformThreadId valid_thread_id_; -}; - -} // namespace net - -#endif // NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 03e33ad3e..228e689 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc
@@ -59,7 +59,7 @@ #include "net/ssl/ssl_key_logger.h" #endif -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include "net/cert_net/nss_ocsp.h" #endif @@ -396,7 +396,7 @@ // this will behave as if Reset(NULL) was called. void Reset(STACK_OF(X509)* chain); - // Note that when USE_OPENSSL is defined, OSCertHandle is X509* + // Note that when USE_OPENSSL_CERTS is defined, OSCertHandle is X509* scoped_refptr<X509Certificate> AsOSChain() const; size_t size() const { @@ -877,7 +877,7 @@ DCHECK(!ssl_); DCHECK(!transport_bio_); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) if (ssl_config_.cert_io_enabled) { // TODO(davidben): Move this out of SSLClientSocket. See // https://crbug.com/539520.
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index b3088999..63884f4 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc
@@ -4,8 +4,15 @@ #include "net/socket/ssl_client_socket.h" +#include <errno.h> +#include <string.h> + #include <utility> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + #include "base/callback_helpers.h" #include "base/files/file_util.h" #include "base/location.h" @@ -15,6 +22,7 @@ #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" #include "base/time/time.h" +#include "crypto/scoped_openssl_types.h" #include "net/base/address_list.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -45,23 +53,13 @@ #include "net/ssl/ssl_config_service.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/ssl/ssl_info.h" +#include "net/ssl/test_ssl_private_key.h" #include "net/test/cert_test_util.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" -#if defined(USE_OPENSSL) -#include <errno.h> -#include <openssl/bio.h> -#include <openssl/evp.h> -#include <openssl/pem.h> -#include <string.h> - -#include "crypto/scoped_openssl_types.h" -#include "net/ssl/test_ssl_private_key.h" -#endif - using testing::_; using testing::Return; using testing::Truly; @@ -1503,35 +1501,6 @@ ASSERT_EQ(ERR_IO_PENDING, rv); ASSERT_FALSE(read_callback.have_result()); -#if !defined(USE_OPENSSL) - // NSS follows a pattern where a call to PR_Write will only consume as - // much data as it can encode into application data records before the - // internal memio buffer is full, which should only fill if writing a large - // amount of data and the underlying transport is blocked. Once this happens, - // NSS will return (total size of all application data records it wrote) - 1, - // with the caller expected to resume with the remaining unsent data. - // - // This causes SSLClientSocketNSS::Write to return that it wrote some data - // before it will return ERR_IO_PENDING, so make an extra call to Write() to - // get the socket in the state needed for the test below. - // - // This is not needed for OpenSSL, because for OpenSSL, - // SSL_MODE_ENABLE_PARTIAL_WRITE is not specified - thus - // SSLClientSocketOpenSSL::Write() will not return until all of - // |request_buffer| has been written to the underlying BIO (although not - // necessarily the underlying transport). - rv = callback.GetResult(raw_sock->Write(request_buffer.get(), - request_buffer->BytesRemaining(), - callback.callback())); - ASSERT_LT(0, rv); - request_buffer->DidConsume(rv); - - // Guard to ensure that |request_buffer| was larger than all of the internal - // buffers (transport, memio, NSS) along the way - otherwise the next call - // to Write() will crash with an invalid buffer. - ASSERT_LT(0, request_buffer->BytesRemaining()); -#endif - // Attempt to write the remaining data. NSS will not be able to consume the // application data because the internal buffers are full, while OpenSSL will // return that its blocked because the underlying transport is blocked. @@ -1641,15 +1610,8 @@ raw_transport->UnblockReadResult(); rv = read_callback.WaitForResult(); -#if defined(USE_OPENSSL) // Should still read bytes despite the write error. EXPECT_LT(0, rv); -#else - // NSS attempts to flush the write buffer in PR_Read on an SSL socket before - // pumping the read state machine, unless configured with SSL_ENABLE_FDX, so - // the write error stops future reads. - EXPECT_EQ(ERR_CONNECTION_RESET, rv); -#endif } // Tests that SSLClientSocket fails the handshake if the underlying @@ -2273,8 +2235,6 @@ request_info->cert_authorities[1]); } -// cert_key_types is currently only populated on OpenSSL. -#if defined(USE_OPENSSL) TEST_F(SSLClientSocketCertRequestInfoTest, CertKeyTypes) { SpawnedTestServer::SSLOptions ssl_options; ssl_options.request_client_certificate = true; @@ -2286,7 +2246,6 @@ EXPECT_EQ(CLIENT_CERT_RSA_SIGN, request_info->cert_key_types[0]); EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, request_info->cert_key_types[1]); } -#endif // defined(USE_OPENSSL) TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledTLSExtension) { SpawnedTestServer::SSLOptions ssl_options; @@ -2839,9 +2798,6 @@ SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM; server_options.npn_protocols.push_back(std::string("http/1.1")); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); ASSERT_NO_FATAL_FAILURE( TestFalseStart(server_options, client_config, true)); @@ -2870,9 +2826,6 @@ SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM; server_options.npn_protocols.push_back(std::string("http/1.1")); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); ASSERT_NO_FATAL_FAILURE( TestFalseStart(server_options, client_config, false)); @@ -2887,9 +2840,6 @@ SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM; server_options.npn_protocols.push_back(std::string("http/1.1")); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); // DHE is only advertised when deprecated ciphers are enabled. client_config.deprecated_cipher_suites_enabled = true; @@ -2905,9 +2855,6 @@ SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128; server_options.npn_protocols.push_back(std::string("http/1.1")); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, false)); } @@ -2922,9 +2869,6 @@ SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM; server_options.npn_protocols.push_back(std::string("http/1.1")); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); // Let a full handshake complete with False Start. @@ -2955,9 +2899,6 @@ ASSERT_TRUE(StartTestServer(server_options)); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); // Start a handshake up to the server Finished message. @@ -3012,9 +2953,6 @@ ASSERT_TRUE(StartTestServer(server_options)); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); // Start a handshake up to the server Finished message. @@ -3161,10 +3099,6 @@ ASSERT_TRUE(StartTestServer(server_options)); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP2); - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP2); client_config.npn_protos.push_back(kProtoHTTP11); @@ -3185,10 +3119,6 @@ ASSERT_TRUE(StartTestServer(server_options)); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoSPDY31); - client_config.alpn_protos.push_back(kProtoHTTP2); -#endif client_config.npn_protos.push_back(kProtoSPDY31); client_config.npn_protos.push_back(kProtoHTTP2); @@ -3210,10 +3140,6 @@ ASSERT_TRUE(StartTestServer(server_options)); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP2); - client_config.alpn_protos.push_back(kProtoSPDY31); -#endif client_config.npn_protos.push_back(kProtoHTTP2); client_config.npn_protos.push_back(kProtoSPDY31); @@ -3251,9 +3177,6 @@ ASSERT_TRUE(StartTestServer(server_options)); SSLConfig client_config; -#if !defined(USE_OPENSSL) - client_config.alpn_protos.push_back(kProtoHTTP11); -#endif client_config.npn_protos.push_back(kProtoHTTP11); int rv; @@ -3265,9 +3188,6 @@ sock_->GetNextProto(&proto)); } -// Client auth is not supported in NSS ports. -#if defined(USE_OPENSSL) - namespace { // Loads a PEM-encoded private key file into a SSLPrivateKey object. @@ -3370,6 +3290,5 @@ sock_->Disconnect(); EXPECT_FALSE(sock_->IsConnected()); } -#endif // defined(USE_OPENSSL) } // namespace net
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc deleted file mode 100644 index 17f7d62..0000000 --- a/net/socket/ssl_server_socket_nss.cc +++ /dev/null
@@ -1,982 +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. - -#include "net/socket/ssl_server_socket_nss.h" - -#include <utility> - -#if defined(OS_WIN) -#include <winsock2.h> -#endif - -#if defined(USE_SYSTEM_SSL) -#include <dlfcn.h> -#endif -#if defined(OS_MACOSX) -#include <Security/Security.h> -#endif -#include <certdb.h> -#include <cryptohi.h> -#include <hasht.h> -#include <keyhi.h> -#include <nspr.h> -#include <nss.h> -#include <pk11pub.h> -#include <secerr.h> -#include <sechash.h> -#include <ssl.h> -#include <sslerr.h> -#include <sslproto.h> - -#include <limits> - -#include "base/callback_helpers.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "crypto/nss_util_internal.h" -#include "crypto/rsa_private_key.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/log/net_log.h" -#include "net/socket/nss_ssl_util.h" - -// SSL plaintext fragments are shorter than 16KB. Although the record layer -// overhead is allowed to be 2K + 5 bytes, in practice the overhead is much -// smaller than 1KB. So a 17KB buffer should be large enough to hold an -// entire SSL record. -static const int kRecvBufferSize = 17 * 1024; -static const int kSendBufferSize = 17 * 1024; - -#define GotoState(s) next_handshake_state_ = s - -namespace net { - -namespace { - -bool g_nss_server_sockets_init = false; - -class NSSSSLServerInitSingleton { - public: - NSSSSLServerInitSingleton() { - EnsureNSSSSLInit(); - - SSL_ConfigServerSessionIDCache(64, 28800, 28800, NULL); - g_nss_server_sockets_init = true; - } - - ~NSSSSLServerInitSingleton() { - SSL_ShutdownServerSessionIDCache(); - g_nss_server_sockets_init = false; - } -}; - -static base::LazyInstance<NSSSSLServerInitSingleton>::Leaky - g_nss_ssl_server_init_singleton = LAZY_INSTANCE_INITIALIZER; - -class SSLServerSocketNSS : public SSLServerSocket { - public: - // See comments on CreateSSLServerSocket for details of how these - // parameters are used. - SSLServerSocketNSS(std::unique_ptr<StreamSocket> socket, - X509Certificate* certificate, - const crypto::RSAPrivateKey& key, - const SSLServerConfig& ssl_server_config); - ~SSLServerSocketNSS() override; - - // SSLServerSocket interface. - int Handshake(const CompletionCallback& callback) override; - - // SSLSocket interface. - int ExportKeyingMaterial(const base::StringPiece& label, - bool has_context, - const base::StringPiece& context, - unsigned char* out, - unsigned int outlen) override; - - // Socket interface (via StreamSocket). - int Read(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override; - int Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override; - int SetReceiveBufferSize(int32_t size) override; - int SetSendBufferSize(int32_t size) override; - - // StreamSocket implementation. - int Connect(const CompletionCallback& callback) override; - void Disconnect() override; - bool IsConnected() const override; - bool IsConnectedAndIdle() const override; - int GetPeerAddress(IPEndPoint* address) const override; - int GetLocalAddress(IPEndPoint* address) const override; - const BoundNetLog& NetLog() const override; - void SetSubresourceSpeculation() override; - void SetOmniboxSpeculation() override; - bool WasEverUsed() const override; - bool WasNpnNegotiated() const override; - NextProto GetNegotiatedProtocol() const override; - bool GetSSLInfo(SSLInfo* ssl_info) override; - void GetConnectionAttempts(ConnectionAttempts* out) const override; - void ClearConnectionAttempts() override {} - void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} - int64_t GetTotalReceivedBytes() const override; - - private: - enum State { - STATE_NONE, - STATE_HANDSHAKE, - }; - - int InitializeSSLOptions(); - - void OnSendComplete(int result); - void OnRecvComplete(int result); - void OnHandshakeIOComplete(int result); - - int BufferSend(); - void BufferSendComplete(int result); - int BufferRecv(); - void BufferRecvComplete(int result); - bool DoTransportIO(); - int DoPayloadRead(); - int DoPayloadWrite(); - - int DoHandshakeLoop(int last_io_result); - int DoReadLoop(int result); - int DoWriteLoop(int result); - int DoHandshake(); - void DoHandshakeCallback(int result); - void DoReadCallback(int result); - void DoWriteCallback(int result); - - static SECStatus OwnAuthCertHandler(void* arg, - PRFileDesc* socket, - PRBool checksig, - PRBool is_server); - static void HandshakeCallback(PRFileDesc* socket, void* arg); - - int Init(); - - // Members used to send and receive buffer. - bool transport_send_busy_; - bool transport_recv_busy_; - - scoped_refptr<IOBuffer> recv_buffer_; - - BoundNetLog net_log_; - - CompletionCallback user_handshake_callback_; - CompletionCallback user_read_callback_; - CompletionCallback user_write_callback_; - - // Used by Read function. - scoped_refptr<IOBuffer> user_read_buf_; - int user_read_buf_len_; - - // Used by Write function. - scoped_refptr<IOBuffer> user_write_buf_; - int user_write_buf_len_; - - // The NSS SSL state machine - PRFileDesc* nss_fd_; - - // Buffers for the network end of the SSL state machine - memio_Private* nss_bufs_; - - // StreamSocket for sending and receiving data. - std::unique_ptr<StreamSocket> transport_socket_; - - // Options for the SSL socket. - SSLServerConfig ssl_server_config_; - - // Certificate for the server. - scoped_refptr<X509Certificate> cert_; - - // Private key used by the server. - std::unique_ptr<crypto::RSAPrivateKey> key_; - - State next_handshake_state_; - bool completed_handshake_; - - DISALLOW_COPY_AND_ASSIGN(SSLServerSocketNSS); -}; - -SSLServerSocketNSS::SSLServerSocketNSS( - std::unique_ptr<StreamSocket> transport_socket, - X509Certificate* cert, - const crypto::RSAPrivateKey& key, - const SSLServerConfig& ssl_server_config) - : transport_send_busy_(false), - transport_recv_busy_(false), - user_read_buf_len_(0), - user_write_buf_len_(0), - nss_fd_(NULL), - nss_bufs_(NULL), - transport_socket_(std::move(transport_socket)), - ssl_server_config_(ssl_server_config), - cert_(cert), - key_(key.Copy()), - next_handshake_state_(STATE_NONE), - completed_handshake_(false) { - CHECK(key_); -} - -SSLServerSocketNSS::~SSLServerSocketNSS() { - if (nss_fd_ != NULL) { - PR_Close(nss_fd_); - nss_fd_ = NULL; - } -} - -int SSLServerSocketNSS::Handshake(const CompletionCallback& callback) { - net_log_.BeginEvent(NetLog::TYPE_SSL_SERVER_HANDSHAKE); - - int rv = Init(); - if (rv != OK) { - LOG(ERROR) << "Failed to initialize NSS"; - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv); - return rv; - } - - rv = InitializeSSLOptions(); - if (rv != OK) { - LOG(ERROR) << "Failed to initialize SSL options"; - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv); - return rv; - } - - // Set peer address. TODO(hclam): This should be in a separate method. - PRNetAddr peername; - memset(&peername, 0, sizeof(peername)); - peername.raw.family = AF_INET; - memio_SetPeerName(nss_fd_, &peername); - - GotoState(STATE_HANDSHAKE); - rv = DoHandshakeLoop(OK); - if (rv == ERR_IO_PENDING) { - user_handshake_callback_ = callback; - } else { - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv); - } - - return rv > OK ? OK : rv; -} - -int SSLServerSocketNSS::ExportKeyingMaterial(const base::StringPiece& label, - bool has_context, - const base::StringPiece& context, - unsigned char* out, - unsigned int outlen) { - if (!IsConnected()) - return ERR_SOCKET_NOT_CONNECTED; - SECStatus result = SSL_ExportKeyingMaterial( - nss_fd_, label.data(), label.size(), has_context, - reinterpret_cast<const unsigned char*>(context.data()), - context.length(), out, outlen); - if (result != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_ExportKeyingMaterial", ""); - return MapNSSError(PORT_GetError()); - } - return OK; -} - -int SSLServerSocketNSS::Connect(const CompletionCallback& callback) { - NOTIMPLEMENTED(); - return ERR_NOT_IMPLEMENTED; -} - -int SSLServerSocketNSS::Read(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { - DCHECK(user_read_callback_.is_null()); - DCHECK(user_handshake_callback_.is_null()); - DCHECK(!user_read_buf_); - DCHECK(nss_bufs_); - DCHECK(!callback.is_null()); - - user_read_buf_ = buf; - user_read_buf_len_ = buf_len; - - DCHECK(completed_handshake_); - - int rv = DoReadLoop(OK); - - if (rv == ERR_IO_PENDING) { - user_read_callback_ = callback; - } else { - user_read_buf_ = NULL; - user_read_buf_len_ = 0; - } - return rv; -} - -int SSLServerSocketNSS::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { - DCHECK(user_write_callback_.is_null()); - DCHECK(!user_write_buf_); - DCHECK(nss_bufs_); - DCHECK(!callback.is_null()); - - user_write_buf_ = buf; - user_write_buf_len_ = buf_len; - - int rv = DoWriteLoop(OK); - - if (rv == ERR_IO_PENDING) { - user_write_callback_ = callback; - } else { - user_write_buf_ = NULL; - user_write_buf_len_ = 0; - } - return rv; -} - -int SSLServerSocketNSS::SetReceiveBufferSize(int32_t size) { - return transport_socket_->SetReceiveBufferSize(size); -} - -int SSLServerSocketNSS::SetSendBufferSize(int32_t size) { - return transport_socket_->SetSendBufferSize(size); -} - -bool SSLServerSocketNSS::IsConnected() const { - // TODO(wtc): Find out if we should check transport_socket_->IsConnected() - // as well. - return completed_handshake_; -} - -void SSLServerSocketNSS::Disconnect() { - transport_socket_->Disconnect(); -} - -bool SSLServerSocketNSS::IsConnectedAndIdle() const { - return completed_handshake_ && transport_socket_->IsConnectedAndIdle(); -} - -int SSLServerSocketNSS::GetPeerAddress(IPEndPoint* address) const { - if (!IsConnected()) - return ERR_SOCKET_NOT_CONNECTED; - return transport_socket_->GetPeerAddress(address); -} - -int SSLServerSocketNSS::GetLocalAddress(IPEndPoint* address) const { - if (!IsConnected()) - return ERR_SOCKET_NOT_CONNECTED; - return transport_socket_->GetLocalAddress(address); -} - -const BoundNetLog& SSLServerSocketNSS::NetLog() const { - return net_log_; -} - -void SSLServerSocketNSS::SetSubresourceSpeculation() { - transport_socket_->SetSubresourceSpeculation(); -} - -void SSLServerSocketNSS::SetOmniboxSpeculation() { - transport_socket_->SetOmniboxSpeculation(); -} - -bool SSLServerSocketNSS::WasEverUsed() const { - return transport_socket_->WasEverUsed(); -} - -bool SSLServerSocketNSS::WasNpnNegotiated() const { - NOTIMPLEMENTED(); - return false; -} - -NextProto SSLServerSocketNSS::GetNegotiatedProtocol() const { - // NPN is not supported by this class. - return kProtoUnknown; -} - -bool SSLServerSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { - NOTIMPLEMENTED(); - return false; -} - -void SSLServerSocketNSS::GetConnectionAttempts(ConnectionAttempts* out) const { - out->clear(); -} - -int64_t SSLServerSocketNSS::GetTotalReceivedBytes() const { - NOTIMPLEMENTED(); - return 0; -} - -int SSLServerSocketNSS::InitializeSSLOptions() { - // Transport connected, now hook it up to nss - nss_fd_ = memio_CreateIOLayer(kRecvBufferSize, kSendBufferSize); - if (nss_fd_ == NULL) { - return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR error code. - } - - // Grab pointer to buffers - nss_bufs_ = memio_GetSecret(nss_fd_); - - /* Create SSL state machine */ - /* Push SSL onto our fake I/O socket */ - nss_fd_ = SSL_ImportFD(NULL, nss_fd_); - if (nss_fd_ == NULL) { - LogFailedNSSFunction(net_log_, "SSL_ImportFD", ""); - return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR/NSS error code. - } - // TODO(port): set more ssl options! Check errors! - - int rv; - - if (ssl_server_config_.client_cert_type == - SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT) { - rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", - "SSL_REQUEST_CERTIFICATE"); - return ERR_UNEXPECTED; - } - } - - rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_SECURITY"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL2"); - return ERR_UNEXPECTED; - } - - SSLVersionRange version_range; - version_range.min = ssl_server_config_.version_min; - version_range.max = ssl_server_config_.version_max; - rv = SSL_VersionRangeSet(nss_fd_, &version_range); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_VersionRangeSet", ""); - return ERR_NO_SSL_VERSIONS_ENABLED; - } - - if (ssl_server_config_.require_ecdhe) { - const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers(); - const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers(); - - // Iterate over the cipher suites and disable those that don't use ECDHE. - for (unsigned i = 0; i < num_ciphers; i++) { - SSLCipherSuiteInfo info; - if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) == - SECSuccess) { - if (strcmp(info.keaTypeName, "ECDHE") != 0) { - SSL_CipherPrefSet(nss_fd_, ssl_ciphers[i], PR_FALSE); - } - } - } - } - - for (std::vector<uint16_t>::const_iterator it = - ssl_server_config_.disabled_cipher_suites.begin(); - it != ssl_server_config_.disabled_cipher_suites.end(); ++it) { - // This will fail if the specified cipher is not implemented by NSS, but - // the failure is harmless. - SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE); - } - - // Server socket doesn't need session tickets. - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction( - net_log_, "SSL_OptionSet", "SSL_ENABLE_SESSION_TICKETS"); - } - - // Doing this will force PR_Accept perform handshake as server. - rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_CLIENT"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_SERVER"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUEST_CERTIFICATE"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_CERTIFICATE, PR_FALSE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUIRE_CERTIFICATE"); - return ERR_UNEXPECTED; - } - - rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_AuthCertificateHook", ""); - return ERR_UNEXPECTED; - } - - rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_HandshakeCallback", ""); - return ERR_UNEXPECTED; - } - - // Get a certificate of CERTCertificate structure. - std::string der_string; - if (!X509Certificate::GetDEREncoded(cert_->os_cert_handle(), &der_string)) - return ERR_UNEXPECTED; - - SECItem der_cert; - der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>( - der_string.data())); - der_cert.len = der_string.length(); - der_cert.type = siDERCertBuffer; - - // Parse into a CERTCertificate structure. - CERTCertificate* cert = CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE); - if (!cert) { - LogFailedNSSFunction(net_log_, "CERT_NewTempCertificate", ""); - return MapNSSError(PORT_GetError()); - } - - // Get a key of SECKEYPrivateKey* structure. - std::vector<uint8_t> key_vector; - if (!key_->ExportPrivateKey(&key_vector)) { - CERT_DestroyCertificate(cert); - return ERR_UNEXPECTED; - } - - SECKEYPrivateKeyStr* private_key = NULL; - PK11SlotInfo* slot = PK11_GetInternalSlot(); - if (!slot) { - CERT_DestroyCertificate(cert); - return ERR_UNEXPECTED; - } - - SECItem der_private_key_info; - der_private_key_info.data = - const_cast<unsigned char*>(&key_vector.front()); - der_private_key_info.len = key_vector.size(); - // The server's RSA private key must be imported into NSS with the - // following key usage bits: - // - KU_KEY_ENCIPHERMENT, required for the RSA key exchange algorithm. - // - KU_DIGITAL_SIGNATURE, required for the DHE_RSA and ECDHE_RSA key - // exchange algorithms. - const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; - rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( - slot, &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE, - key_usage, &private_key, NULL); - PK11_FreeSlot(slot); - if (rv != SECSuccess) { - CERT_DestroyCertificate(cert); - return ERR_UNEXPECTED; - } - - // Assign server certificate and private key. - SSLKEAType cert_kea = NSS_FindCertKEAType(cert); - rv = SSL_ConfigSecureServer(nss_fd_, cert, private_key, cert_kea); - CERT_DestroyCertificate(cert); - SECKEY_DestroyPrivateKey(private_key); - - if (rv != SECSuccess) { - PRErrorCode prerr = PR_GetError(); - LOG(ERROR) << "Failed to config SSL server: " << prerr; - LogFailedNSSFunction(net_log_, "SSL_ConfigureSecureServer", ""); - return ERR_UNEXPECTED; - } - - // Tell SSL we're a server; needed if not letting NSPR do socket I/O - rv = SSL_ResetHandshake(nss_fd_, PR_TRUE); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_ResetHandshake", ""); - return ERR_UNEXPECTED; - } - - return OK; -} - -void SSLServerSocketNSS::OnSendComplete(int result) { - if (next_handshake_state_ == STATE_HANDSHAKE) { - // In handshake phase. - OnHandshakeIOComplete(result); - return; - } - - // TODO(byungchul): This state machine is not correct. Copy the state machine - // of SSLClientSocketNSS::OnSendComplete() which handles it better. - if (!completed_handshake_) - return; - - if (user_write_buf_) { - int rv = DoWriteLoop(result); - if (rv != ERR_IO_PENDING) - DoWriteCallback(rv); - } else { - // Ensure that any queued ciphertext is flushed. - DoTransportIO(); - } -} - -void SSLServerSocketNSS::OnRecvComplete(int result) { - if (next_handshake_state_ == STATE_HANDSHAKE) { - // In handshake phase. - OnHandshakeIOComplete(result); - return; - } - - // Network layer received some data, check if client requested to read - // decrypted data. - if (!user_read_buf_ || !completed_handshake_) - return; - - int rv = DoReadLoop(result); - if (rv != ERR_IO_PENDING) - DoReadCallback(rv); -} - -void SSLServerSocketNSS::OnHandshakeIOComplete(int result) { - int rv = DoHandshakeLoop(result); - if (rv == ERR_IO_PENDING) - return; - - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv); - if (!user_handshake_callback_.is_null()) - DoHandshakeCallback(rv); -} - -// Return 0 for EOF, -// > 0 for bytes transferred immediately, -// < 0 for error (or the non-error ERR_IO_PENDING). -int SSLServerSocketNSS::BufferSend(void) { - if (transport_send_busy_) - return ERR_IO_PENDING; - - const char* buf1; - const char* buf2; - unsigned int len1, len2; - if (memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2)) { - // The error code itself is ignored, so just return ERR_ABORTED. - return ERR_ABORTED; - } - const size_t len = len1 + len2; - - int rv = 0; - if (len) { - scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len)); - memcpy(send_buffer->data(), buf1, len1); - memcpy(send_buffer->data() + len1, buf2, len2); - rv = transport_socket_->Write( - send_buffer.get(), len, - base::Bind(&SSLServerSocketNSS::BufferSendComplete, - base::Unretained(this))); - if (rv == ERR_IO_PENDING) { - transport_send_busy_ = true; - } else { - memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv)); - } - } - - return rv; -} - -void SSLServerSocketNSS::BufferSendComplete(int result) { - memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result)); - transport_send_busy_ = false; - OnSendComplete(result); -} - -int SSLServerSocketNSS::BufferRecv(void) { - if (transport_recv_busy_) return ERR_IO_PENDING; - - char* buf; - int nb = memio_GetReadParams(nss_bufs_, &buf); - int rv; - if (!nb) { - // buffer too full to read into, so no I/O possible at moment - rv = ERR_IO_PENDING; - } else { - recv_buffer_ = new IOBuffer(nb); - rv = transport_socket_->Read( - recv_buffer_.get(), nb, - base::Bind(&SSLServerSocketNSS::BufferRecvComplete, - base::Unretained(this))); - if (rv == ERR_IO_PENDING) { - transport_recv_busy_ = true; - } else { - if (rv > 0) - memcpy(buf, recv_buffer_->data(), rv); - memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv)); - recv_buffer_ = NULL; - } - } - return rv; -} - -void SSLServerSocketNSS::BufferRecvComplete(int result) { - if (result > 0) { - char* buf; - memio_GetReadParams(nss_bufs_, &buf); - memcpy(buf, recv_buffer_->data(), result); - } - recv_buffer_ = NULL; - memio_PutReadResult(nss_bufs_, MapErrorToNSS(result)); - transport_recv_busy_ = false; - OnRecvComplete(result); -} - -// Do as much network I/O as possible between the buffer and the -// transport socket. Return true if some I/O performed, false -// otherwise (error or ERR_IO_PENDING). -bool SSLServerSocketNSS::DoTransportIO() { - bool network_moved = false; - if (nss_bufs_ != NULL) { - int rv; - // Read and write as much data as we can. The loop is neccessary - // because Write() may return synchronously. - do { - rv = BufferSend(); - if (rv > 0) - network_moved = true; - } while (rv > 0); - if (BufferRecv() >= 0) - network_moved = true; - } - return network_moved; -} - -int SSLServerSocketNSS::DoPayloadRead() { - DCHECK(user_read_buf_); - DCHECK_GT(user_read_buf_len_, 0); - int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_); - if (rv >= 0) - return rv; - PRErrorCode prerr = PR_GetError(); - if (prerr == PR_WOULD_BLOCK_ERROR) { - return ERR_IO_PENDING; - } - rv = MapNSSError(prerr); - net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, - CreateNetLogSSLErrorCallback(rv, prerr)); - return rv; -} - -int SSLServerSocketNSS::DoPayloadWrite() { - DCHECK(user_write_buf_); - int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_); - if (rv >= 0) - return rv; - PRErrorCode prerr = PR_GetError(); - if (prerr == PR_WOULD_BLOCK_ERROR) { - return ERR_IO_PENDING; - } - rv = MapNSSError(prerr); - net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, - CreateNetLogSSLErrorCallback(rv, prerr)); - return rv; -} - -int SSLServerSocketNSS::DoHandshakeLoop(int last_io_result) { - int rv = last_io_result; - do { - // Default to STATE_NONE for next state. - // (This is a quirk carried over from the windows - // implementation. It makes reading the logs a bit harder.) - // State handlers can and often do call GotoState just - // to stay in the current state. - State state = next_handshake_state_; - GotoState(STATE_NONE); - switch (state) { - case STATE_HANDSHAKE: - rv = DoHandshake(); - break; - case STATE_NONE: - default: - rv = ERR_UNEXPECTED; - LOG(DFATAL) << "unexpected state " << state; - break; - } - - // Do the actual network I/O - bool network_moved = DoTransportIO(); - if (network_moved && next_handshake_state_ == STATE_HANDSHAKE) { - // In general we exit the loop if rv is ERR_IO_PENDING. In this - // special case we keep looping even if rv is ERR_IO_PENDING because - // the transport IO may allow DoHandshake to make progress. - rv = OK; // This causes us to stay in the loop. - } - } while (rv != ERR_IO_PENDING && next_handshake_state_ != STATE_NONE); - return rv; -} - -int SSLServerSocketNSS::DoReadLoop(int result) { - DCHECK(completed_handshake_); - DCHECK(next_handshake_state_ == STATE_NONE); - - if (result < 0) - return result; - - if (!nss_bufs_) { - LOG(DFATAL) << "!nss_bufs_"; - int rv = ERR_UNEXPECTED; - net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, - CreateNetLogSSLErrorCallback(rv, 0)); - return rv; - } - - bool network_moved; - int rv; - do { - rv = DoPayloadRead(); - network_moved = DoTransportIO(); - } while (rv == ERR_IO_PENDING && network_moved); - return rv; -} - -int SSLServerSocketNSS::DoWriteLoop(int result) { - DCHECK(completed_handshake_); - DCHECK_EQ(next_handshake_state_, STATE_NONE); - - if (result < 0) - return result; - - if (!nss_bufs_) { - LOG(DFATAL) << "!nss_bufs_"; - int rv = ERR_UNEXPECTED; - net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, - CreateNetLogSSLErrorCallback(rv, 0)); - return rv; - } - - bool network_moved; - int rv; - do { - rv = DoPayloadWrite(); - network_moved = DoTransportIO(); - } while (rv == ERR_IO_PENDING && network_moved); - return rv; -} - -int SSLServerSocketNSS::DoHandshake() { - int net_error = OK; - SECStatus rv = SSL_ForceHandshake(nss_fd_); - - if (rv == SECSuccess) { - completed_handshake_ = true; - } else { - PRErrorCode prerr = PR_GetError(); - net_error = MapNSSError(prerr); - - // If not done, stay in this state - if (net_error == ERR_IO_PENDING) { - GotoState(STATE_HANDSHAKE); - } else { - LOG(ERROR) << "handshake failed; NSS error code " << prerr - << ", net_error " << net_error; - net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR, - CreateNetLogSSLErrorCallback(net_error, prerr)); - } - } - return net_error; -} - -void SSLServerSocketNSS::DoHandshakeCallback(int rv) { - DCHECK_NE(rv, ERR_IO_PENDING); - base::ResetAndReturn(&user_handshake_callback_).Run(rv > OK ? OK : rv); -} - -void SSLServerSocketNSS::DoReadCallback(int rv) { - DCHECK(rv != ERR_IO_PENDING); - DCHECK(!user_read_callback_.is_null()); - - user_read_buf_ = NULL; - user_read_buf_len_ = 0; - base::ResetAndReturn(&user_read_callback_).Run(rv); -} - -void SSLServerSocketNSS::DoWriteCallback(int rv) { - DCHECK(rv != ERR_IO_PENDING); - DCHECK(!user_write_callback_.is_null()); - - user_write_buf_ = NULL; - user_write_buf_len_ = 0; - base::ResetAndReturn(&user_write_callback_).Run(rv); -} - -// static -// NSS calls this if an incoming certificate needs to be verified. -// Do nothing but return SECSuccess. -// This is called only in full handshake mode. -// Peer certificate is retrieved in HandshakeCallback() later, which is called -// in full handshake mode or in resumption handshake mode. -SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg, - PRFileDesc* socket, - PRBool checksig, - PRBool is_server) { - // TODO(hclam): Implement. - // Tell NSS to not verify the certificate. - return SECSuccess; -} - -// static -// NSS calls this when handshake is completed. -// After the SSL handshake is finished we need to verify the certificate. -void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket, void* arg) { - // TODO(hclam): Implement. -} - -int SSLServerSocketNSS::Init() { - // Initialize the NSS SSL library in a threadsafe way. This also - // initializes the NSS base library. - EnsureNSSSSLInit(); - if (!NSS_IsInitialized()) - return ERR_UNEXPECTED; - - EnableSSLServerSockets(); - return OK; -} - -} // namespace - -std::unique_ptr<SSLServerContext> CreateSSLServerContext( - X509Certificate* certificate, - const crypto::RSAPrivateKey& key, - const SSLServerConfig& ssl_server_config) { - return std::unique_ptr<SSLServerContext>( - new SSLServerContextNSS(certificate, key, ssl_server_config)); -} - -SSLServerContextNSS::SSLServerContextNSS( - X509Certificate* certificate, - const crypto::RSAPrivateKey& key, - const SSLServerConfig& ssl_server_config) - : ssl_server_config_(ssl_server_config), - cert_(certificate), - key_(key.Copy()) { - CHECK(key_); -} - -SSLServerContextNSS::~SSLServerContextNSS() {} - -std::unique_ptr<SSLServerSocket> SSLServerContextNSS::CreateSSLServerSocket( - std::unique_ptr<StreamSocket> socket) { - DCHECK(g_nss_server_sockets_init) << "EnableSSLServerSockets() has not been" - << " called yet!"; - - return std::unique_ptr<SSLServerSocket>(new SSLServerSocketNSS( - std::move(socket), cert_.get(), *key_, ssl_server_config_)); -} - -void EnableSSLServerSockets() { - g_nss_ssl_server_init_singleton.Get(); -} - -} // namespace net
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h deleted file mode 100644 index 9464cede..0000000 --- a/net/socket/ssl_server_socket_nss.h +++ /dev/null
@@ -1,49 +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. - -#ifndef NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_ -#define NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_ - -#include <certt.h> -#include <keyt.h> -#include <nspr.h> -#include <nss.h> -#include <stdint.h> - -#include <memory> - -#include "base/macros.h" -#include "net/base/completion_callback.h" -#include "net/base/host_port_pair.h" -#include "net/base/nss_memio.h" -#include "net/log/net_log.h" -#include "net/socket/ssl_server_socket.h" -#include "net/ssl/ssl_server_config.h" - -namespace net { - -class SSLServerContextNSS : public SSLServerContext { - public: - SSLServerContextNSS(X509Certificate* certificate, - const crypto::RSAPrivateKey& key, - const SSLServerConfig& ssl_server_config); - ~SSLServerContextNSS() override; - - std::unique_ptr<SSLServerSocket> CreateSSLServerSocket( - std::unique_ptr<StreamSocket> socket) override; - - private: - // Options for the SSL socket. - SSLServerConfig ssl_server_config_; - - // Certificate for the server. - scoped_refptr<X509Certificate> cert_; - - // Private key used by the server. - std::unique_ptr<crypto::RSAPrivateKey> key_; -}; - -} // namespace net - -#endif // NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc index 74e06ab..32ecfc0 100644 --- a/net/socket/ssl_server_socket_unittest.cc +++ b/net/socket/ssl_server_socket_unittest.cc
@@ -20,6 +20,10 @@ #include <queue> #include <utility> +#include <openssl/evp.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + #include "base/callback_helpers.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" @@ -65,12 +69,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" -#if defined(USE_OPENSSL) -#include <openssl/evp.h> -#include <openssl/ssl.h> -#include <openssl/x509.h> -#endif - namespace net { namespace { @@ -397,7 +395,6 @@ ASSERT_TRUE(server_socket_); } -#if defined(USE_OPENSSL) void ConfigureClientCertsForClient(const char* cert_file_name, const char* private_key_file_name) { client_ssl_config_.send_client_cert = true; @@ -458,7 +455,6 @@ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector)); return key; } -#endif std::unique_ptr<FakeDataChannel> channel_1_; std::unique_ptr<FakeDataChannel> channel_2_; @@ -520,9 +516,6 @@ EXPECT_TRUE(is_aead); } -// NSS ports don't support client certificates and have a global session cache. -#if defined(USE_OPENSSL) - // This test makes sure the session cache is working. TEST_F(SSLServerSocketTest, HandshakeCached) { ASSERT_NO_FATAL_FAILURE(CreateContext()); @@ -865,7 +858,6 @@ EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT, handshake_callback2.GetResult(server_ret2)); } -#endif // defined(USE_OPENSSL) TEST_F(SSLServerSocketTest, DataTransfer) { ASSERT_NO_FATAL_FAILURE(CreateContext());
diff --git a/net/ssl/channel_id_service.cc b/net/ssl/channel_id_service.cc index 163a56b..830a4a43 100644 --- a/net/ssl/channel_id_service.cc +++ b/net/ssl/channel_id_service.cc
@@ -31,10 +31,6 @@ #include "net/cert/x509_util.h" #include "url/gurl.h" -#if !defined(USE_OPENSSL) -#include <private/pprthred.h> // PR_DetachThread -#endif - namespace net { namespace { @@ -146,16 +142,6 @@ int error = ERR_FAILED; std::unique_ptr<ChannelIDStore::ChannelID> channel_id = GenerateChannelID(server_identifier_, &error); -#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. - // The threads in our thread pool terminate after we have called - // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets - // segfaults on shutdown when the threads' thread-specific data - // destructors run. - PR_DetachThread(); -#endif origin_task_runner_->PostTask( FROM_HERE, base::Bind(callback_, server_identifier_, error, base::Passed(&channel_id)));
diff --git a/net/ssl/ssl_cipher_suite_names.cc b/net/ssl/ssl_cipher_suite_names.cc index 2bfe72a..f6b5460 100644 --- a/net/ssl/ssl_cipher_suite_names.cc +++ b/net/ssl/ssl_cipher_suite_names.cc
@@ -4,11 +4,10 @@ #include "net/ssl/ssl_cipher_suite_names.h" -#if defined(USE_OPENSSL) -#include <openssl/ssl.h> -#endif #include <stdlib.h> +#include <openssl/ssl.h> + #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -424,7 +423,6 @@ } const char* ECCurveName(uint16_t cipher_suite, int key_exchange_info) { -#if defined(USE_OPENSSL) int key_exchange, cipher, mac; if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac)) return nullptr; @@ -436,9 +434,6 @@ return nullptr; } return SSL_get_curve_name(key_exchange_info); -#else - return nullptr; -#endif } } // namespace net
diff --git a/net/ssl/token_binding_nss.cc b/net/ssl/token_binding_nss.cc deleted file mode 100644 index aa2dd09..0000000 --- a/net/ssl/token_binding_nss.cc +++ /dev/null
@@ -1,51 +0,0 @@ -// 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 "token_binding.h" - -#include "net/base/net_errors.h" - -namespace net { - -bool IsTokenBindingSupported() { - return false; -} - -bool SignTokenBindingEkm(base::StringPiece ekm, - crypto::ECPrivateKey* key, - std::vector<uint8_t>* out) { - return false; -} - -Error BuildTokenBindingMessageFromTokenBindings( - const std::vector<base::StringPiece>& token_bindings, - std::string* out) { - NOTREACHED(); - return ERR_NOT_IMPLEMENTED; -} - -Error BuildTokenBinding(TokenBindingType type, - crypto::ECPrivateKey* key, - const std::vector<uint8_t>& ekm, - std::string* out) { - NOTREACHED(); - return ERR_NOT_IMPLEMENTED; -} - -TokenBinding::TokenBinding() {} - -bool ParseTokenBindingMessage(base::StringPiece token_binding_message, - std::vector<TokenBinding>* token_bindings) { - NOTREACHED(); - return false; -} - -bool VerifyEKMSignature(base::StringPiece ec_point, - base::StringPiece signature, - base::StringPiece ekm) { - NOTREACHED(); - return false; -} - -} // namespace net
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc index d994b00..be9cb8a 100644 --- a/net/test/embedded_test_server/embedded_test_server_unittest.cc +++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -31,7 +31,7 @@ #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include "net/cert_net/nss_ocsp.h" #endif @@ -123,7 +123,7 @@ } void SetUp() override { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) // This is needed so NSS's HTTP client functions are initialized on the // right thread. These tests create SSLClientSockets on a different thread. // TODO(davidben): Initialization can't be deferred to SSLClientSocket. See @@ -146,7 +146,7 @@ void TearDown() override { if (server_->Started()) ASSERT_TRUE(server_->ShutdownAndWaitUntilComplete()); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) ShutdownNSSHttpIO(); #endif } @@ -498,7 +498,7 @@ class EmbeddedTestServerThreadingTest : public testing::TestWithParam<ThreadingTestParams> { void SetUp() override { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) // This is needed so NSS's HTTP client functions are initialized on the // right thread. These tests create SSLClientSockets on a different thread. // TODO(davidben): Initialization can't be deferred to SSLClientSocket. See @@ -509,7 +509,7 @@ } void TearDown() override { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) ShutdownNSSHttpIO(); #endif }
diff --git a/net/test/net_test_suite.cc b/net/test/net_test_suite.cc index 561f149..8b0942b 100644 --- a/net/test/net_test_suite.cc +++ b/net/test/net_test_suite.cc
@@ -10,7 +10,7 @@ #include "net/spdy/spdy_session.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include "net/cert_net/nss_ocsp.h" #endif @@ -33,7 +33,7 @@ } void NetTestSuite::Shutdown() { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) net::ShutdownNSSHttpIO(); #endif
diff --git a/net/test/run_all_unittests.cc b/net/test/run_all_unittests.cc index 5d605092..20f5a68 100644 --- a/net/test/run_all_unittests.cc +++ b/net/test/run_all_unittests.cc
@@ -59,11 +59,6 @@ NetTestSuite test_suite(argc, argv); ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(false); -#if defined(OS_WIN) && !defined(USE_OPENSSL) - // We want to be sure to init NSPR on the main thread. - crypto::EnsureNSPRInit(); -#endif - // Enable support for SSL server sockets, which must be done while // single-threaded. net::EnableSSLServerSockets();
diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh deleted file mode 100755 index 4724233..0000000 --- a/net/third_party/nss/patches/applypatches.sh +++ /dev/null
@@ -1,34 +0,0 @@ -#!/bin/sh -# 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. - -# Run this script in the nss/lib/ssl directory in a NSS source tree. -# -# Point patches_dir to the src/net/third_party/nss/patches directory in a -# chromium source tree. -patches_dir=/Users/sleevi/development/chromium/src/net/third_party/nss/patches - -patch -p2 < $patches_dir/cachecerts.patch - -patch -p2 < $patches_dir/didhandshakeresume.patch - -patch -p2 < $patches_dir/getrequestedclientcerttypes.patch - -patch -p2 < $patches_dir/restartclientauth.patch - -patch -p2 < $patches_dir/channelid.patch - -patch -p2 < $patches_dir/tlsunique.patch - -patch -p2 < $patches_dir/secretexporterlocks.patch - -patch -p2 < $patches_dir/cachelocks.patch - -patch -p2 < $patches_dir/cipherorder.patch - -patch -p2 < $patches_dir/sessioncache.patch - -patch -p2 < $patches_dir/reorderextensions.patch - -patch -p2 < $patches_dir/nobypass.patch
diff --git a/net/third_party/nss/patches/cachecerts.patch b/net/third_party/nss/patches/cachecerts.patch deleted file mode 100644 index 196bb278..0000000 --- a/net/third_party/nss/patches/cachecerts.patch +++ /dev/null
@@ -1,124 +0,0 @@ -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index c3698f3..b8d4784 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -47,6 +47,7 @@ - - static SECStatus ssl3_AuthCertificate(sslSocket *ss); - static void ssl3_CleanupPeerCerts(sslSocket *ss); -+static void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid); - static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, - PK11SlotInfo *serverKeySlot); - static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); -@@ -7102,6 +7103,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) - /* copy the peer cert from the SID */ - if (sid->peerCert != NULL) { - ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); -+ ssl3_CopyPeerCertsFromSID(ss, sid); - } - - /* NULL value for PMS because we are reusing the old MS */ -@@ -8266,6 +8268,44 @@ ssl3_KEAAllowsSessionTicket(SSL3KeyExchangeAlgorithm kea) - }; - } - -+static void -+ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid) -+{ -+ PLArenaPool *arena; -+ ssl3CertNode *lastCert = NULL; -+ ssl3CertNode *certs = NULL; -+ int i; -+ -+ if (!sid->peerCertChain[0]) -+ return; -+ PORT_Assert(!ss->ssl3.peerCertArena); -+ PORT_Assert(!ss->ssl3.peerCertChain); -+ ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); -+ for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { -+ ssl3CertNode *c = PORT_ArenaNew(arena, ssl3CertNode); -+ c->cert = CERT_DupCertificate(sid->peerCertChain[i]); -+ c->next = NULL; -+ if (lastCert) { -+ lastCert->next = c; -+ } else { -+ certs = c; -+ } -+ lastCert = c; -+ } -+ ss->ssl3.peerCertChain = certs; -+} -+ -+static void -+ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, sslSessionID *sid) -+{ -+ int i = 0; -+ ssl3CertNode *c = certs; -+ for (; i < MAX_PEER_CERT_CHAIN_SIZE && c; i++, c = c->next) { -+ PORT_Assert(!sid->peerCertChain[i]); -+ sid->peerCertChain[i] = CERT_DupCertificate(c->cert); -+ } -+} -+ - /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete - * ssl3 Client Hello message. - * Caller must hold Handshake and RecvBuf locks. -@@ -8886,6 +8926,7 @@ compression_found: - ss->sec.ci.sid = sid; - if (sid->peerCert != NULL) { - ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); -+ ssl3_CopyPeerCertsFromSID(ss, sid); - } - - /* -@@ -11240,6 +11281,7 @@ ssl3_AuthCertificate(sslSocket *ss) - } - - ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); -+ ssl3_CopyPeerCertsToSID(ss->ssl3.peerCertChain, ss->sec.ci.sid); - - if (!ss->sec.isServer) { - CERTCertificate *cert = ss->sec.peerCert; -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index bce9437..10361a0 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -614,6 +614,8 @@ typedef enum { never_cached, - invalid_cache /* no longer in any cache. */ - } Cached; - -+#define MAX_PEER_CERT_CHAIN_SIZE 8 -+ - struct sslSessionIDStr { - /* The global cache lock must be held when accessing these members when the - * sid is in any cache. -@@ -628,6 +630,7 @@ struct sslSessionIDStr { - */ - - CERTCertificate *peerCert; -+ CERTCertificate *peerCertChain[MAX_PEER_CERT_CHAIN_SIZE]; - SECItemArray peerCertStatus; /* client only */ - const char *peerID; /* client only */ - const char *urlSvrName; /* client only */ -diff --git a/lib/ssl/sslnonce.c b/lib/ssl/sslnonce.c -index 85031c4..3216892 100644 ---- a/lib/ssl/sslnonce.c -+++ b/lib/ssl/sslnonce.c -@@ -167,6 +167,7 @@ lock_cache(void) - static void - ssl_DestroySID(sslSessionID *sid) - { -+ int i; - SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached)); - PORT_Assert(sid->references == 0); - PORT_Assert(sid->cached != in_client_cache); -@@ -200,6 +201,9 @@ ssl_DestroySID(sslSessionID *sid) - if (sid->peerCert) { - CERT_DestroyCertificate(sid->peerCert); - } -+ for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { -+ CERT_DestroyCertificate(sid->peerCertChain[i]); -+ } - if (sid->peerCertStatus.items) { - SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE); - }
diff --git a/net/third_party/nss/patches/cachelocks.patch b/net/third_party/nss/patches/cachelocks.patch deleted file mode 100644 index 9ba646b..0000000 --- a/net/third_party/nss/patches/cachelocks.patch +++ /dev/null
@@ -1,239 +0,0 @@ -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index 1394542..d7d186a 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -6049,7 +6049,6 @@ SSL3_ShutdownServerCache(void) - } - - PZ_Unlock(symWrapKeysLock); -- ssl_FreeSessionCacheLocks(); - return SECSuccess; - } - -@@ -6102,7 +6101,7 @@ getWrappingKey(sslSocket *ss, - - pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[exchKeyType]; - -- ssl_InitSessionCacheLocks(PR_TRUE); -+ ssl_InitSessionCacheLocks(); - - PZ_Lock(symWrapKeysLock); - -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index d47eb28..c0e3a0b 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -2029,9 +2029,7 @@ extern SECStatus ssl_InitSymWrapKeysLock(void); - - extern SECStatus ssl_FreeSymWrapKeysLock(void); - --extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit); -- --extern SECStatus ssl_FreeSessionCacheLocks(void); -+extern SECStatus ssl_InitSessionCacheLocks(void); - - /**************** DTLS-specific functions **************/ - extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg); -diff --git a/lib/ssl/sslnonce.c b/lib/ssl/sslnonce.c -index 4804cb8..99591cc 100644 ---- a/lib/ssl/sslnonce.c -+++ b/lib/ssl/sslnonce.c -@@ -35,93 +35,55 @@ static PZLock *cacheLock = NULL; - #define LOCK_CACHE lock_cache() - #define UNLOCK_CACHE PZ_Unlock(cacheLock) - --static SECStatus --ssl_InitClientSessionCacheLock(void) --{ -- cacheLock = PZ_NewLock(nssILockCache); -- return cacheLock ? SECSuccess : SECFailure; --} -- --static SECStatus --ssl_FreeClientSessionCacheLock(void) --{ -- if (cacheLock) { -- PZ_DestroyLock(cacheLock); -- cacheLock = NULL; -- return SECSuccess; -- } -- PORT_SetError(SEC_ERROR_NOT_INITIALIZED); -- return SECFailure; --} -- --static PRBool LocksInitializedEarly = PR_FALSE; -+static PRCallOnceType lockOnce; - -+/* FreeSessionCacheLocks is a callback from NSS_RegisterShutdown which destroys -+ * the session cache locks on shutdown and resets them to their initial -+ * state. */ - static SECStatus --FreeSessionCacheLocks() -+FreeSessionCacheLocks(void *appData, void *nssData) - { -- SECStatus rv1, rv2; -- rv1 = ssl_FreeSymWrapKeysLock(); -- rv2 = ssl_FreeClientSessionCacheLock(); -- if ((SECSuccess == rv1) && (SECSuccess == rv2)) { -- return SECSuccess; -- } -- return SECFailure; --} -+ static const PRCallOnceType pristineCallOnce; -+ SECStatus rv; - --static SECStatus --InitSessionCacheLocks(void) --{ -- SECStatus rv1, rv2; -- PRErrorCode rc; -- rv1 = ssl_InitSymWrapKeysLock(); -- rv2 = ssl_InitClientSessionCacheLock(); -- if ((SECSuccess == rv1) && (SECSuccess == rv2)) { -- return SECSuccess; -- } -- rc = PORT_GetError(); -- FreeSessionCacheLocks(); -- PORT_SetError(rc); -- return SECFailure; --} -- --/* free the session cache locks if they were initialized early */ --SECStatus --ssl_FreeSessionCacheLocks() --{ -- PORT_Assert(PR_TRUE == LocksInitializedEarly); -- if (!LocksInitializedEarly) { -+ if (!cacheLock) { - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return SECFailure; - } -- FreeSessionCacheLocks(); -- LocksInitializedEarly = PR_FALSE; -- return SECSuccess; --} - --static PRCallOnceType lockOnce; -+ PZ_DestroyLock(cacheLock); -+ cacheLock = NULL; - --/* free the session cache locks if they were initialized lazily */ --static SECStatus --ssl_ShutdownLocks(void *appData, void *nssData) --{ -- PORT_Assert(PR_FALSE == LocksInitializedEarly); -- if (LocksInitializedEarly) { -- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); -- return SECFailure; -+ rv = ssl_FreeSymWrapKeysLock(); -+ if (rv != SECSuccess) { -+ return rv; - } -- FreeSessionCacheLocks(); -- memset(&lockOnce, 0, sizeof(lockOnce)); -+ -+ lockOnce = pristineCallOnce; - return SECSuccess; - } - -+/* InitSessionCacheLocks is called, protected by lockOnce, to create the -+ * session cache locks. */ - static PRStatus --initSessionCacheLocksLazily(void) -+InitSessionCacheLocks(void) - { -- SECStatus rv = InitSessionCacheLocks(); -- if (SECSuccess != rv) { -+ SECStatus rv; -+ -+ cacheLock = PZ_NewLock(nssILockCache); -+ if (cacheLock == NULL) { - return PR_FAILURE; - } -- rv = NSS_RegisterShutdown(ssl_ShutdownLocks, NULL); -+ rv = ssl_InitSymWrapKeysLock(); -+ if (rv != SECSuccess) { -+ PRErrorCode error = PORT_GetError(); -+ PZ_DestroyLock(cacheLock); -+ cacheLock = NULL; -+ PORT_SetError(error); -+ return PR_FAILURE; -+ } -+ -+ rv = NSS_RegisterShutdown(FreeSessionCacheLocks, NULL); - PORT_Assert(SECSuccess == rv); - if (SECSuccess != rv) { - return PR_FAILURE; -@@ -129,35 +91,19 @@ initSessionCacheLocksLazily(void) - return PR_SUCCESS; - } - --/* lazyInit means that the call is not happening during a 1-time -- * initialization function, but rather during dynamic, lazy initialization -- */ - SECStatus --ssl_InitSessionCacheLocks(PRBool lazyInit) -+ssl_InitSessionCacheLocks() - { -- if (LocksInitializedEarly) { -- return SECSuccess; -- } -- -- if (lazyInit) { -- return (PR_SUCCESS == -- PR_CallOnce(&lockOnce, initSessionCacheLocksLazily)) -- ? SECSuccess -- : SECFailure; -- } -- -- if (SECSuccess == InitSessionCacheLocks()) { -- LocksInitializedEarly = PR_TRUE; -- return SECSuccess; -- } -- -- return SECFailure; -+ return (PR_SUCCESS == -+ PR_CallOnce(&lockOnce, InitSessionCacheLocks)) -+ ? SECSuccess -+ : SECFailure; - } - - static void - lock_cache(void) - { -- ssl_InitSessionCacheLocks(PR_TRUE); -+ ssl_InitSessionCacheLocks(); - PZ_Lock(cacheLock); - } - -diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c -index da1f93f..e3f749e 100644 ---- a/lib/ssl/sslsnce.c -+++ b/lib/ssl/sslsnce.c -@@ -1344,7 +1344,7 @@ SSL_ConfigServerSessionIDCache(int maxCacheEntries, - PRUint32 ssl3_timeout, - const char *directory) - { -- ssl_InitSessionCacheLocks(PR_FALSE); -+ ssl_InitSessionCacheLocks(); - return SSL_ConfigServerSessionIDCacheInstance(&globalCache, - maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE); - } -@@ -1458,7 +1458,7 @@ SSL_ConfigServerSessionIDCacheWithOpt( - PRBool enableMPCache) - { - if (!enableMPCache) { -- ssl_InitSessionCacheLocks(PR_FALSE); -+ ssl_InitSessionCacheLocks(); - return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, - ssl2_timeout, ssl3_timeout, directory, PR_FALSE, - maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries); -@@ -1502,7 +1502,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString) - return SECSuccess; /* already done. */ - } - -- ssl_InitSessionCacheLocks(PR_FALSE); -+ ssl_InitSessionCacheLocks(); - - ssl_sid_lookup = ServerSessionIDLookup; - ssl_sid_cache = ServerSessionIDCache;
diff --git a/net/third_party/nss/patches/channelid.patch b/net/third_party/nss/patches/channelid.patch deleted file mode 100644 index 674d4ee..0000000 --- a/net/third_party/nss/patches/channelid.patch +++ /dev/null
@@ -1,704 +0,0 @@ -diff --git a/lib/ssl/SSLerrs.h b/lib/ssl/SSLerrs.h -index 15bf0b4..555e629 100644 ---- a/lib/ssl/SSLerrs.h -+++ b/lib/ssl/SSLerrs.h -@@ -465,3 +465,12 @@ ER3(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 145), - - ER3(SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS, (SSL_ERROR_BASE + 146), - "SSL received a malformed Encrypted Extensions handshake message.") -+ -+ER3(SSL_ERROR_BAD_CHANNEL_ID_DATA, (SSL_ERROR_BASE + 147), -+ "SSL received a malformed TLS Channel ID extension.") -+ -+ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 148), -+ "The application provided an invalid TLS Channel ID key.") -+ -+ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 149), -+ "The application could not get a TLS Channel ID.") -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index aa4a3e5..870a8cc 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -1142,6 +1142,34 @@ SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc *socket, - SSL_IMPORT SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd, - PRBool *last_handshake_resumed); - -+/* See SSL_SetClientChannelIDCallback for usage. If the callback returns -+ * SECWouldBlock then SSL_RestartHandshakeAfterChannelIDReq should be called in -+ * the future to restart the handshake. On SECSuccess, the callback must have -+ * written a P-256, EC key pair to |*out_public_key| and |*out_private_key|. */ -+typedef SECStatus(PR_CALLBACK *SSLClientChannelIDCallback)( -+ void *arg, -+ PRFileDesc *fd, -+ SECKEYPublicKey **out_public_key, -+ SECKEYPrivateKey **out_private_key); -+ -+/* SSL_RestartHandshakeAfterChannelIDReq attempts to restart the handshake -+ * after a ChannelID callback returned SECWouldBlock. -+ * -+ * This function takes ownership of |channelIDPub| and |channelID|. */ -+SSL_IMPORT SECStatus SSL_RestartHandshakeAfterChannelIDReq( -+ PRFileDesc *fd, -+ SECKEYPublicKey *channelIDPub, -+ SECKEYPrivateKey *channelID); -+ -+/* SSL_SetClientChannelIDCallback sets a callback function that will be called -+ * once the server's ServerHello has been processed. This is only applicable to -+ * a client socket and setting this callback causes the TLS Channel ID -+ * extension to be advertised. */ -+SSL_IMPORT SECStatus SSL_SetClientChannelIDCallback( -+ PRFileDesc *fd, -+ SSLClientChannelIDCallback callback, -+ void *arg); -+ - /* - ** How long should we wait before retransmitting the next flight of - ** the DTLS handshake? Returns SECFailure if not DTLS or not in a -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index 2a2e644..a2beec2 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -57,6 +57,7 @@ static SECStatus ssl3_InitState(sslSocket *ss); - - static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); - static SECStatus ssl3_SendNextProto(sslSocket *ss); -+static SECStatus ssl3_SendChannelIDEncryptedExtensions(sslSocket *ss); - static SECStatus ssl3_SendFinished(sslSocket *ss, PRInt32 flags); - static SECStatus ssl3_SendServerHelloDone(sslSocket *ss); - static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss); -@@ -6762,6 +6763,15 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) - ss->ssl3.clientPrivateKey = NULL; - } - -+ if (ss->ssl3.channelID != NULL) { -+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID); -+ ss->ssl3.channelID = NULL; -+ } -+ if (ss->ssl3.channelIDPub != NULL) { -+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); -+ ss->ssl3.channelIDPub = NULL; -+ } -+ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (temp < 0) { - goto loser; /* alert has been sent */ -@@ -7111,7 +7121,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) - if (rv != SECSuccess) { - goto alert_loser; /* err code was set */ - } -- return SECSuccess; -+ goto winner; - } while (0); - - if (sid_match) -@@ -7166,6 +7176,27 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) - PORT_Assert(ss->ssl3.hs.kea_def->ephemeral); - ss->ssl3.hs.ws = wait_server_key; - } -+ -+winner: -+ /* If we will need a ChannelID key then we make the callback now. This -+ * allows the handshake to be restarted cleanly if the callback returns -+ * SECWouldBlock. */ -+ if (ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { -+ rv = ss->getChannelID(ss->getChannelIDArg, ss->fd, -+ &ss->ssl3.channelIDPub, &ss->ssl3.channelID); -+ if (rv == SECWouldBlock) { -+ ssl3_SetAlwaysBlock(ss); -+ return rv; -+ } -+ if (rv != SECSuccess || -+ ss->ssl3.channelIDPub == NULL || -+ ss->ssl3.channelID == NULL) { -+ PORT_SetError(SSL_ERROR_GET_CHANNEL_ID_FAILED); -+ desc = internal_error; -+ goto alert_loser; -+ } -+ } -+ - return SECSuccess; - - alert_loser: -@@ -8096,7 +8127,14 @@ ssl3_SendClientSecondRound(sslSocket *ss) - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } -+ } - -+ rv = ssl3_SendChannelIDEncryptedExtensions(ss); -+ if (rv != SECSuccess) { -+ goto loser; /* err code was set. */ -+ } -+ -+ if (!ss->firstHsDone) { - if (ss->opt.enableFalseStart) { - if (!ss->ssl3.hs.authCertificatePending) { - /* When we fix bug 589047, we will need to know whether we are -@@ -8133,6 +8171,33 @@ ssl3_SendClientSecondRound(sslSocket *ss) - - ssl_ReleaseXmitBufLock(ss); /*******************************/ - -+ if (!ss->ssl3.hs.isResuming && -+ ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { -+ /* If we are negotiating ChannelID on a full handshake then we record -+ * the handshake hashes in |sid| at this point. They will be needed in -+ * the event that we resume this session and use ChannelID on the -+ * resumption handshake. */ -+ SSL3Hashes hashes; -+ SECItem *originalHandshakeHash = -+ &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; -+ PORT_Assert(ss->sec.ci.sid->cached == never_cached); -+ -+ ssl_GetSpecReadLock(ss); -+ PORT_Assert(ss->version > SSL_LIBRARY_VERSION_3_0); -+ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); -+ ssl_ReleaseSpecReadLock(ss); -+ if (rv != SECSuccess) { -+ return rv; -+ } -+ -+ PORT_Assert(originalHandshakeHash->len == 0); -+ originalHandshakeHash->data = PORT_Alloc(hashes.len); -+ if (!originalHandshakeHash->data) -+ return SECFailure; -+ originalHandshakeHash->len = hashes.len; -+ memcpy(originalHandshakeHash->data, hashes.u.raw, hashes.len); -+ } -+ - if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) - ss->ssl3.hs.ws = wait_new_session_ticket; - else -@@ -11763,6 +11828,184 @@ ssl3_RecordKeyLog(sslSocket *ss) - } - - /* called from ssl3_SendClientSecondRound -+ * ssl3_HandleFinished -+ */ -+static SECStatus -+ssl3_SendChannelIDEncryptedExtensions(sslSocket *ss) -+{ -+ static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; -+ static const char CHANNEL_ID_RESUMPTION_MAGIC[] = "Resumption"; -+ /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: -+ * SEQUENCE -+ * SEQUENCE -+ * OID id-ecPublicKey -+ * OID prime256v1 -+ * BIT STRING, length 66, 0 trailing bits: 0x04 -+ * -+ * The 0x04 in the BIT STRING is the prefix for an uncompressed, X9.62 -+ * public key. Following that are the two field elements as 32-byte, -+ * big-endian numbers, as required by the Channel ID. */ -+ static const unsigned char P256_SPKI_PREFIX[] = { -+ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, -+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, -+ 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, -+ 0x42, 0x00, 0x04 -+ }; -+ /* ChannelIDs are always 128 bytes long: 64 bytes of P-256 public key and 64 -+ * bytes of ECDSA signature. */ -+ static const int CHANNEL_ID_PUBLIC_KEY_LENGTH = 64; -+ static const int CHANNEL_ID_LENGTH = 128; -+ -+ SECStatus rv = SECFailure; -+ SECItem *spki = NULL; -+ SSL3Hashes hashes; -+ const unsigned char *pub_bytes; -+ unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + -+ sizeof(CHANNEL_ID_RESUMPTION_MAGIC) + -+ sizeof(SSL3Hashes) * 2]; -+ size_t signed_data_len; -+ unsigned char digest[SHA256_LENGTH]; -+ SECItem digest_item; -+ unsigned char signature[64]; -+ SECItem signature_item; -+ -+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); -+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); -+ -+ if (ss->ssl3.channelID == NULL) -+ return SECSuccess; -+ -+ PORT_Assert(ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)); -+ -+ if (SECKEY_GetPrivateKeyType(ss->ssl3.channelID) != ecKey || -+ PK11_SignatureLen(ss->ssl3.channelID) != sizeof(signature)) { -+ PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); -+ rv = SECFailure; -+ goto loser; -+ } -+ -+ ssl_GetSpecReadLock(ss); -+ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); -+ ssl_ReleaseSpecReadLock(ss); -+ -+ if (rv != SECSuccess) -+ goto loser; -+ -+ rv = ssl3_AppendHandshakeHeader(ss, channelid_encrypted_extensions, -+ 2 + 2 + CHANNEL_ID_LENGTH); -+ if (rv != SECSuccess) -+ goto loser; /* error code set by AppendHandshakeHeader */ -+ rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); -+ if (rv != SECSuccess) -+ goto loser; /* error code set by AppendHandshake */ -+ rv = ssl3_AppendHandshakeNumber(ss, CHANNEL_ID_LENGTH, 2); -+ if (rv != SECSuccess) -+ goto loser; /* error code set by AppendHandshake */ -+ -+ spki = SECKEY_EncodeDERSubjectPublicKeyInfo(ss->ssl3.channelIDPub); -+ -+ if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH || -+ memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX)) != 0) { -+ PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); -+ rv = SECFailure; -+ goto loser; -+ } -+ -+ pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); -+ -+ signed_data_len = 0; -+ memcpy(signed_data + signed_data_len, CHANNEL_ID_MAGIC, -+ sizeof(CHANNEL_ID_MAGIC)); -+ signed_data_len += sizeof(CHANNEL_ID_MAGIC); -+ if (ss->ssl3.hs.isResuming) { -+ SECItem *originalHandshakeHash = -+ &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; -+ PORT_Assert(originalHandshakeHash->len > 0); -+ -+ memcpy(signed_data + signed_data_len, CHANNEL_ID_RESUMPTION_MAGIC, -+ sizeof(CHANNEL_ID_RESUMPTION_MAGIC)); -+ signed_data_len += sizeof(CHANNEL_ID_RESUMPTION_MAGIC); -+ memcpy(signed_data + signed_data_len, originalHandshakeHash->data, -+ originalHandshakeHash->len); -+ signed_data_len += originalHandshakeHash->len; -+ } -+ memcpy(signed_data + signed_data_len, hashes.u.raw, hashes.len); -+ signed_data_len += hashes.len; -+ -+ rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, signed_data_len); -+ if (rv != SECSuccess) -+ goto loser; -+ -+ digest_item.data = digest; -+ digest_item.len = sizeof(digest); -+ -+ signature_item.data = signature; -+ signature_item.len = sizeof(signature); -+ -+ rv = PK11_Sign(ss->ssl3.channelID, &signature_item, &digest_item); -+ if (rv != SECSuccess) -+ goto loser; -+ -+ rv = ssl3_AppendHandshake(ss, pub_bytes, CHANNEL_ID_PUBLIC_KEY_LENGTH); -+ if (rv != SECSuccess) -+ goto loser; -+ rv = ssl3_AppendHandshake(ss, signature, sizeof(signature)); -+ -+loser: -+ if (spki) -+ SECITEM_FreeItem(spki, PR_TRUE); -+ if (ss->ssl3.channelID) { -+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID); -+ ss->ssl3.channelID = NULL; -+ } -+ if (ss->ssl3.channelIDPub) { -+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); -+ ss->ssl3.channelIDPub = NULL; -+ } -+ -+ return rv; -+} -+ -+/* ssl3_RestartHandshakeAfterChannelIDReq is called to restart a handshake -+ * after a ChannelID callback returned SECWouldBlock. At this point we have -+ * processed the server's ServerHello but not yet any further messages. We will -+ * always get a message from the server after a ServerHello so either they are -+ * waiting in the buffer or we'll get network I/O. */ -+SECStatus -+ssl3_RestartHandshakeAfterChannelIDReq(sslSocket *ss, -+ SECKEYPublicKey *channelIDPub, -+ SECKEYPrivateKey *channelID) -+{ -+ if (ss->handshake == 0) { -+ SECKEY_DestroyPublicKey(channelIDPub); -+ SECKEY_DestroyPrivateKey(channelID); -+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); -+ return SECFailure; -+ } -+ -+ if (channelIDPub == NULL || -+ channelID == NULL) { -+ if (channelIDPub) -+ SECKEY_DestroyPublicKey(channelIDPub); -+ if (channelID) -+ SECKEY_DestroyPrivateKey(channelID); -+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR); -+ return SECFailure; -+ } -+ -+ if (ss->ssl3.channelID) -+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID); -+ if (ss->ssl3.channelIDPub) -+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); -+ -+ ss->handshake = ssl_GatherRecord1stHandshake; -+ ss->ssl3.channelID = channelID; -+ ss->ssl3.channelIDPub = channelIDPub; -+ -+ return SECSuccess; -+} -+ -+/* called from ssl3_SendClientSecondRound - * ssl3_HandleClientHello - * ssl3_HandleFinished - */ -@@ -12030,11 +12273,16 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, - flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; - } - -- if (!isServer && !ss->firstHsDone) { -- rv = ssl3_SendNextProto(ss); -- if (rv != SECSuccess) { -- goto xmit_loser; /* err code was set. */ -+ if (!isServer) { -+ if (!ss->firstHsDone) { -+ rv = ssl3_SendNextProto(ss); -+ if (rv != SECSuccess) { -+ goto xmit_loser; /* err code was set. */ -+ } - } -+ rv = ssl3_SendChannelIDEncryptedExtensions(ss); -+ if (rv != SECSuccess) -+ goto xmit_loser; /* err code was set. */ - } - - if (IS_DTLS(ss)) { -@@ -13658,6 +13906,11 @@ ssl3_DestroySSL3Info(sslSocket *ss) - if (ss->ssl3.clientPrivateKey != NULL) - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - -+ if (ss->ssl3.channelID) -+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID); -+ if (ss->ssl3.channelIDPub) -+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); -+ - if (ss->ssl3.peerCertArena != NULL) - ssl3_CleanupPeerCerts(ss); - -diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c -index 2e99a40..2ffe77b 100644 ---- a/lib/ssl/ssl3ext.c -+++ b/lib/ssl/ssl3ext.c -@@ -73,6 +73,10 @@ static SECStatus ssl3_ClientHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); - static SECStatus ssl3_ServerHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); -+static SECStatus ssl3_ClientHandleChannelIDXtn(sslSocket *ss, -+ PRUint16 ex_type, SECItem *data); -+static PRInt32 ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append, -+ PRUint32 maxBytes); - static PRInt32 ssl3_ServerSendStatusRequestXtn(sslSocket *ss, - PRBool append, PRUint32 maxBytes); - static SECStatus ssl3_ServerHandleStatusRequestXtn(sslSocket *ss, -@@ -298,6 +302,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { - { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, - { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn }, - { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn }, -+ { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, - { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, - { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, - { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn }, -@@ -329,6 +334,7 @@ static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] - { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, - { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn }, - { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn }, -+ { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, - { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, - { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, - { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn }, -@@ -981,6 +987,61 @@ ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) - } - - static SECStatus -+ssl3_ClientHandleChannelIDXtn(sslSocket *ss, PRUint16 ex_type, -+ SECItem *data) -+{ -+ PORT_Assert(ss->getChannelID != NULL); -+ -+ if (data->len) { -+ PORT_SetError(SSL_ERROR_BAD_CHANNEL_ID_DATA); -+ return SECFailure; -+ } -+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; -+ return SECSuccess; -+} -+ -+static PRInt32 -+ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append, -+ PRUint32 maxBytes) -+{ -+ PRInt32 extension_length = 4; -+ -+ if (!ss->getChannelID) -+ return 0; -+ -+ if (maxBytes < extension_length) { -+ PORT_Assert(0); -+ return 0; -+ } -+ -+ if (ss->sec.ci.sid->cached != never_cached && -+ ss->sec.ci.sid->u.ssl3.originalHandshakeHash.len == 0) { -+ /* We can't do ChannelID on a connection if we're resuming and didn't -+ * do ChannelID on the original connection: without ChannelID on the -+ * original connection we didn't record the handshake hashes needed for -+ * the signature. */ -+ return 0; -+ } -+ -+ if (append) { -+ SECStatus rv; -+ rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); -+ if (rv != SECSuccess) -+ goto loser; -+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); -+ if (rv != SECSuccess) -+ goto loser; -+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = -+ ssl_channel_id_xtn; -+ } -+ -+ return extension_length; -+ -+loser: -+ return -1; -+} -+ -+static SECStatus - ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) - { -diff --git a/lib/ssl/ssl3prot.h b/lib/ssl/ssl3prot.h -index e637d11..928d059 100644 ---- a/lib/ssl/ssl3prot.h -+++ b/lib/ssl/ssl3prot.h -@@ -140,7 +140,8 @@ typedef enum { - client_key_exchange = 16, - finished = 20, - certificate_status = 22, -- next_proto = 67 -+ next_proto = 67, -+ channelid_encrypted_extensions = 203 - } SSL3HandshakeType; - - typedef struct { -diff --git a/lib/ssl/sslauth.c b/lib/ssl/sslauth.c -index 7fb4dc5..e78a513 100644 ---- a/lib/ssl/sslauth.c -+++ b/lib/ssl/sslauth.c -@@ -221,6 +221,25 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, - return SECSuccess; - } - -+SECStatus -+SSL_SetClientChannelIDCallback(PRFileDesc *fd, -+ SSLClientChannelIDCallback callback, -+ void *arg) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback", -+ SSL_GETPID(), fd)); -+ return SECFailure; -+ } -+ -+ ss->getChannelID = callback; -+ ss->getChannelIDArg = arg; -+ -+ return SECSuccess; -+} -+ - /* NEED LOCKS IN HERE. */ - SECStatus - SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) -diff --git a/lib/ssl/sslerr.h b/lib/ssl/sslerr.h -index f806359..299951c 100644 ---- a/lib/ssl/sslerr.h -+++ b/lib/ssl/sslerr.h -@@ -220,6 +220,11 @@ typedef enum { - SSL_ERROR_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 144), - SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 145), - SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 146), -+ -+ SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 147), -+ SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 148), -+ SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 149), -+ - SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ - } SSLErrorCodes; - #endif /* NO_SECURITY_ERROR_ENUM */ -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index dad75b2..4607655 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -710,6 +710,14 @@ struct sslSessionIDStr { - - SECItem srvName; - -+ /* originalHandshakeHash contains the hash of the original, full -+ * handshake prior to the server's final flow. This is either a -+ * SHA-1/MD5 combination (for TLS < 1.2) or the TLS PRF hash (for -+ * TLS 1.2). This is recorded and used only when ChannelID is -+ * negotiated as it's used to bind the ChannelID signature on the -+ * resumption handshake to the original handshake. */ -+ SECItem originalHandshakeHash; -+ - /* Signed certificate timestamps received in a TLS extension. - ** (used only in client). - */ -@@ -1025,6 +1033,9 @@ struct ssl3StateStr { - CERTCertificateList *clientCertChain; /* used by client */ - PRBool sendEmptyCert; /* used by client */ - -+ SECKEYPrivateKey *channelID; /* used by client */ -+ SECKEYPublicKey *channelIDPub; /* used by client */ -+ - int policy; - /* This says what cipher suites we can do, and should - * be either SSL_ALLOWED or SSL_RESTRICTED -@@ -1322,6 +1333,9 @@ struct sslSocketStr { - SSLNextProtoCallback nextProtoCallback; - void *nextProtoArg; - -+ SSLClientChannelIDCallback getChannelID; -+ void *getChannelIDArg; -+ - PRIntervalTime rTimeout; /* timeout for NSPR I/O */ - PRIntervalTime wTimeout; /* timeout for NSPR I/O */ - PRIntervalTime cTimeout; /* timeout for NSPR I/O */ -@@ -1712,6 +1726,12 @@ extern SECStatus ssl3_RestartHandshakeAfterCertReq(struct sslSocketStr *ss, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain); -+ -+extern SECStatus ssl3_RestartHandshakeAfterChannelIDReq( -+ sslSocket *ss, -+ SECKEYPublicKey *channelIDPub, -+ SECKEYPrivateKey *channelID); -+ - extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error); - - /* -diff --git a/lib/ssl/sslnonce.c b/lib/ssl/sslnonce.c -index 3216892..4804cb8 100644 ---- a/lib/ssl/sslnonce.c -+++ b/lib/ssl/sslnonce.c -@@ -186,6 +186,9 @@ ssl_DestroySID(sslSessionID *sid) - if (sid->u.ssl3.signedCertTimestamps.data) { - SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE); - } -+ if (sid->u.ssl3.originalHandshakeHash.data) { -+ SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); -+ } - - if (sid->u.ssl3.lock) { - PR_DestroyRWLock(sid->u.ssl3.lock); -diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c -index a087ffc..7ff0a2c 100644 ---- a/lib/ssl/sslsecur.c -+++ b/lib/ssl/sslsecur.c -@@ -1601,6 +1601,41 @@ SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, - return ret; - } - -+SECStatus -+SSL_RestartHandshakeAfterChannelIDReq(PRFileDesc *fd, -+ SECKEYPublicKey *channelIDPub, -+ SECKEYPrivateKey *channelID) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ SECStatus ret; -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in" -+ " SSL_RestartHandshakeAfterChannelIDReq", -+ SSL_GETPID(), fd)); -+ goto loser; -+ } -+ -+ ssl_Get1stHandshakeLock(ss); -+ -+ if (ss->version < SSL_LIBRARY_VERSION_3_0) { -+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); -+ ssl_Release1stHandshakeLock(ss); -+ goto loser; -+ } -+ -+ ret = ssl3_RestartHandshakeAfterChannelIDReq(ss, channelIDPub, -+ channelID); -+ ssl_Release1stHandshakeLock(ss); -+ -+ return ret; -+ -+loser: -+ SECKEY_DestroyPublicKey(channelIDPub); -+ SECKEY_DestroyPrivateKey(channelID); -+ return SECFailure; -+} -+ - /* DO NOT USE. This function was exported in ssl.def with the wrong signature; - * this implementation exists to maintain link-time compatibility. - */ -diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c -index 7f97b14..84c78b3 100644 ---- a/lib/ssl/sslsock.c -+++ b/lib/ssl/sslsock.c -@@ -315,6 +315,8 @@ ssl_DupSocket(sslSocket *os) - ss->canFalseStartCallback = os->canFalseStartCallback; - ss->canFalseStartCallbackData = os->canFalseStartCallbackData; - ss->pkcs11PinArg = os->pkcs11PinArg; -+ ss->getChannelID = os->getChannelID; -+ ss->getChannelIDArg = os->getChannelIDArg; - - /* Create security data */ - rv = ssl_CopySecurityInfo(ss, os); -@@ -2155,6 +2157,10 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) - ss->handshakeCallbackData = sm->handshakeCallbackData; - if (sm->pkcs11PinArg) - ss->pkcs11PinArg = sm->pkcs11PinArg; -+ if (sm->getChannelID) -+ ss->getChannelID = sm->getChannelID; -+ if (sm->getChannelIDArg) -+ ss->getChannelIDArg = sm->getChannelIDArg; - return fd; - loser: - return NULL; -@@ -3643,6 +3649,8 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) - ss->badCertArg = NULL; - ss->pkcs11PinArg = NULL; - ss->ephemeralECDHKeyPair = NULL; -+ ss->getChannelID = NULL; -+ ss->getChannelIDArg = NULL; - - ssl_ChooseOps(ss); - ssl2_InitSocketPolicy(ss); -diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h -index bf722b5..6f26e5f 100644 ---- a/lib/ssl/sslt.h -+++ b/lib/ssl/sslt.h -@@ -249,11 +249,12 @@ typedef enum { - ssl_session_ticket_xtn = 35, - ssl_tls13_key_share_xtn = 40, /* unofficial TODO(ekr) */ - ssl_next_proto_nego_xtn = 13172, -+ ssl_channel_id_xtn = 30032, - ssl_renegotiation_info_xtn = 0xff01, - ssl_tls13_draft_version_xtn = 0xff02 /* experimental number */ - } SSLExtensionType; - --#define SSL_MAX_EXTENSIONS 14 /* doesn't include ssl_padding_xtn. */ -+#define SSL_MAX_EXTENSIONS 15 /* doesn't include ssl_padding_xtn. */ - - typedef enum { - ssl_dhe_group_none = 0,
diff --git a/net/third_party/nss/patches/cipherorder.patch b/net/third_party/nss/patches/cipherorder.patch deleted file mode 100644 index 26e8326..0000000 --- a/net/third_party/nss/patches/cipherorder.patch +++ /dev/null
@@ -1,106 +0,0 @@ -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index 3550580..70665a1 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -387,6 +387,13 @@ SSL_IMPORT SECStatus SSL_DHEGroupPrefSet(PRFileDesc *fd, - */ - SSL_IMPORT SECStatus SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled); - -+/* SSL_CipherOrderSet sets the cipher suite preference order from |ciphers|, -+ * which must be an array of cipher suite ids of length |len|. All the given -+ * cipher suite ids must appear in the array that is returned by -+ * |SSL_GetImplementedCiphers| and may only appear once, at most. */ -+SSL_IMPORT SECStatus SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, -+ unsigned int len); -+ - /* SSLChannelBindingType enumerates the types of supported channel binding - * values. See RFC 5929. */ - typedef enum SSLChannelBindingType { -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index d7d186a..b100b9b 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -13797,6 +13797,46 @@ SSL_SignatureMaxCount() - return MAX_SIGNATURE_ALGORITHMS; - } - -+SECStatus -+ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *ciphers, unsigned int len) -+{ -+ /* |i| iterates over |ciphers| while |done| and |j| iterate over -+ * |ss->cipherSuites|. */ -+ unsigned int i, done; -+ -+ for (i = done = 0; i < len; i++) { -+ PRUint16 id = ciphers[i]; -+ unsigned int existingIndex, j; -+ PRBool found = PR_FALSE; -+ -+ for (j = done; j < ssl_V3_SUITES_IMPLEMENTED; j++) { -+ if (ss->cipherSuites[j].cipher_suite == id) { -+ existingIndex = j; -+ found = PR_TRUE; -+ break; -+ } -+ } -+ -+ if (!found) { -+ continue; -+ } -+ -+ if (existingIndex != done) { -+ const ssl3CipherSuiteCfg temp = ss->cipherSuites[done]; -+ ss->cipherSuites[done] = ss->cipherSuites[existingIndex]; -+ ss->cipherSuites[existingIndex] = temp; -+ } -+ done++; -+ } -+ -+ /* Disable all cipher suites that weren't included. */ -+ for (; done < ssl_V3_SUITES_IMPLEMENTED; done++) { -+ ss->cipherSuites[done].enabled = 0; -+ } -+ -+ return SECSuccess; -+} -+ - /* copy global default policy into socket. */ - void - ssl3_InitSocketPolicy(sslSocket *ss) -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index c0e3a0b..f56ab53 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -1835,6 +1835,8 @@ extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool - extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on); - extern SECStatus ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled); - extern SECStatus ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled); -+extern SECStatus ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *cipher, -+ unsigned int len); - - extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy); - extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy); -diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c -index e312d82..e82c916 100644 ---- a/lib/ssl/sslsock.c -+++ b/lib/ssl/sslsock.c -@@ -1500,6 +1500,19 @@ SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled) - } - - SECStatus -+SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, unsigned int len) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in CipherOrderSet", SSL_GETPID(), -+ fd)); -+ return SECFailure; -+ } -+ return ssl3_CipherOrderSet(ss, ciphers, len); -+} -+ -+SECStatus - SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled) - { - SECStatus rv;
diff --git a/net/third_party/nss/patches/didhandshakeresume.patch b/net/third_party/nss/patches/didhandshakeresume.patch deleted file mode 100644 index 8acb6e71..0000000 --- a/net/third_party/nss/patches/didhandshakeresume.patch +++ /dev/null
@@ -1,40 +0,0 @@ -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index 3974ee8..e905aab 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -1123,6 +1123,9 @@ SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc *socket, - SSLExtensionType extId, - PRBool *yes); - -+SSL_IMPORT SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd, -+ PRBool *last_handshake_resumed); -+ - /* - ** How long should we wait before retransmitting the next flight of - ** the DTLS handshake? Returns SECFailure if not DTLS or not in a -diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c -index cc15406..601df2a 100644 ---- a/lib/ssl/sslsock.c -+++ b/lib/ssl/sslsock.c -@@ -2481,6 +2481,21 @@ SSL_PeerStapledOCSPResponses(PRFileDesc *fd) - return &ss->sec.ci.sid->peerCertStatus; - } - -+SECStatus -+SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_HandshakeResumedSession", -+ SSL_GETPID(), fd)); -+ return SECFailure; -+ } -+ -+ *handshake_resumed = ss->ssl3.hs.isResuming; -+ return SECSuccess; -+} -+ - /************************************************************************/ - /* The following functions are the TOP LEVEL SSL functions. - ** They all get called through the NSPRIOMethods table below.
diff --git a/net/third_party/nss/patches/getrequestedclientcerttypes.patch b/net/third_party/nss/patches/getrequestedclientcerttypes.patch deleted file mode 100644 index d19c2280..0000000 --- a/net/third_party/nss/patches/getrequestedclientcerttypes.patch +++ /dev/null
@@ -1,93 +0,0 @@ -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index e905aab..9e57220 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -896,6 +896,17 @@ SSL_IMPORT SECStatus SSL_ReHandshakeWithTimeout(PRFileDesc *fd, - PRBool flushCache, - PRIntervalTime timeout); - -+/* Returns a SECItem containing the certificate_types field of the -+** CertificateRequest message. Each byte of the data is a TLS -+** ClientCertificateType value, and they are ordered from most preferred to -+** least. This function should only be called from the -+** SSL_GetClientAuthDataHook callback, and will return NULL if called at any -+** other time. The returned value is valid only until the callback returns, and -+** should not be freed. -+*/ -+SSL_IMPORT const SECItem * -+SSL_GetRequestedClientCertificateTypes(PRFileDesc *fd); -+ - #ifdef SSL_DEPRECATED_FUNCTION - /* deprecated! - ** For the server, request a new handshake. For the client, begin a new -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index b8d4784..784f59b 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -7674,6 +7674,9 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) - if (rv != SECSuccess) - goto loser; /* malformed, alert has been sent */ - -+ PORT_Assert(!ss->requestedCertTypes); -+ ss->requestedCertTypes = &cert_types; -+ - if (isTLS12) { - rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &b, &length); - if (rv != SECSuccess) -@@ -7723,6 +7726,7 @@ loser: - PORT_SetError(errCode); - rv = SECFailure; - done: -+ ss->requestedCertTypes = NULL; - if (arena != NULL) - PORT_FreeArena(arena, PR_FALSE); - return rv; -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index 10361a0..5f0e6c9 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -1296,6 +1296,10 @@ struct sslSocketStr { - unsigned int sizeCipherSpecs; - const unsigned char *preferredCipher; - -+ /* TLS ClientCertificateTypes requested during HandleCertificateRequest. */ -+ /* Will be NULL at all other times. */ -+ const SECItem *requestedCertTypes; -+ - ssl3KeyPair *stepDownKeyPair; /* RSA step down keys */ - - const ssl3DHParams *dheParams; /* DHE param */ -diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c -index 601df2a..7f97b14 100644 ---- a/lib/ssl/sslsock.c -+++ b/lib/ssl/sslsock.c -@@ -2496,6 +2496,21 @@ SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) - return SECSuccess; - } - -+const SECItem * -+SSL_GetRequestedClientCertificateTypes(PRFileDesc *fd) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in " -+ "SSL_GetRequestedClientCertificateTypes", -+ SSL_GETPID(), fd)); -+ return NULL; -+ } -+ -+ return ss->requestedCertTypes; -+} -+ - /************************************************************************/ - /* The following functions are the TOP LEVEL SSL functions. - ** They all get called through the NSPRIOMethods table below. -@@ -3610,6 +3625,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) - sc->serverKeyBits = 0; - ss->certStatusArray[i] = NULL; - } -+ ss->requestedCertTypes = NULL; - ss->stepDownKeyPair = NULL; - - ss->dheParams = NULL;
diff --git a/net/third_party/nss/patches/ignorechangecipherspec.patch b/net/third_party/nss/patches/ignorechangecipherspec.patch deleted file mode 100644 index b8e176d..0000000 --- a/net/third_party/nss/patches/ignorechangecipherspec.patch +++ /dev/null
@@ -1,19 +0,0 @@ -Index: ssl/ssl3con.c -=================================================================== ---- ssl/ssl3con.c (revision 274314) -+++ ssl/ssl3con.c (working copy) -@@ -3621,6 +3621,14 @@ - SSL_GETPID(), ss->fd)); - - if (ws != wait_change_cipher) { -+ if (IS_DTLS(ss)) { -+ /* Ignore this because it's out of order. */ -+ SSL_TRC(3, ("%d: SSL3[%d]: discard out of order " -+ "DTLS change_cipher_spec", -+ SSL_GETPID(), ss->fd)); -+ buf->len = 0; -+ return SECSuccess; -+ } - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER); - return SECFailure;
diff --git a/net/third_party/nss/patches/nobypass.patch b/net/third_party/nss/patches/nobypass.patch deleted file mode 100644 index 8896d36..0000000 --- a/net/third_party/nss/patches/nobypass.patch +++ /dev/null
@@ -1,20 +0,0 @@ -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index 7649abe..b6f4987 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -2297,6 +2297,7 @@ fail: - return SECFailure; - } - -+#ifndef NO_PKCS11_BYPASS - /* Returns whether we can bypass PKCS#11 for a given cipher algorithm. - * - * We do not support PKCS#11 bypass for ChaCha20/Poly1305. -@@ -2311,6 +2312,7 @@ ssl3_CanBypassCipher(SSLCipherAlgorithm calg) - return PR_TRUE; - } - } -+#endif - - /* Complete the initialization of all keys, ciphers, MACs and their contexts - * for the pending Cipher Spec.
diff --git a/net/third_party/nss/patches/reorderextensions.patch b/net/third_party/nss/patches/reorderextensions.patch deleted file mode 100644 index 0779e69..0000000 --- a/net/third_party/nss/patches/reorderextensions.patch +++ /dev/null
@@ -1,35 +0,0 @@ -diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c -index 2ffe77b..3b48c9e 100644 ---- a/lib/ssl/ssl3ext.c -+++ b/lib/ssl/ssl3ext.c -@@ -336,10 +336,14 @@ static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] - { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn }, - { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, - { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, -- { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, - { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn }, - { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn }, - { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn }, -+ /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will -+ * time out or terminate the connection if the last extension in the -+ * client hello is empty. They are not intolerant of TLS 1.2, so list -+ * signature_algorithms at the end. See bug 1243641. */ -+ { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, - /* any extra entries will appear as { 0, NULL } */ - }; - -@@ -2690,9 +2694,11 @@ ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength) - } - - extensionLength = 512 - recordLength; -- /* Extensions take at least four bytes to encode. */ -- if (extensionLength < 4) { -- extensionLength = 4; -+ /* Extensions take at least four bytes to encode. Always include at least -+ * one byte of data if including the extension. WebSphere Application -+ * Server 7.0 is intolerant to the last extension being zero-length. */ -+ if (extensionLength < 4 + 1) { -+ extensionLength = 4 + 1; - } - - return extensionLength;
diff --git a/net/third_party/nss/patches/restartclientauth.patch b/net/third_party/nss/patches/restartclientauth.patch deleted file mode 100644 index 811e98c..0000000 --- a/net/third_party/nss/patches/restartclientauth.patch +++ /dev/null
@@ -1,213 +0,0 @@ -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index 9e57220..aa4a3e5 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -516,6 +516,11 @@ SSL_IMPORT SECStatus SSL_ForceHandshake(PRFileDesc *fd); - SSL_IMPORT SECStatus SSL_ForceHandshakeWithTimeout(PRFileDesc *fd, - PRIntervalTime timeout); - -+SSL_IMPORT SECStatus SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, -+ CERTCertificate *cert, -+ SECKEYPrivateKey *key, -+ CERTCertificateList *certChain); -+ - /* - ** Query security status of socket. *on is set to one if security is - ** enabled. *keySize will contain the stream key size used. *issuer will -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index 784f59b..2a2e644 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -7803,6 +7803,85 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss, SECItem *algorithms, - return rv; - } - -+/* -+ * attempt to restart the handshake after asynchronously handling -+ * a request for the client's certificate. -+ * -+ * inputs: -+ * cert Client cert chosen by application. -+ * Note: ssl takes this reference, and does not bump the -+ * reference count. The caller should drop its reference -+ * without calling CERT_DestroyCert after calling this function. -+ * -+ * key Private key associated with cert. This function takes -+ * ownership of the private key, so the caller should drop its -+ * reference without destroying the private key after this -+ * function returns. -+ * -+ * certChain DER-encoded certs, client cert and its signers. -+ * Note: ssl takes this reference, and does not copy the chain. -+ * The caller should drop its reference without destroying the -+ * chain. SSL will free the chain when it is done with it. -+ * -+ * Return value: XXX -+ * -+ * XXX This code only works on the initial handshake on a connection, XXX -+ * It does not work on a subsequent handshake (redo). -+ * -+ * Caller holds 1stHandshakeLock. -+ */ -+SECStatus -+ssl3_RestartHandshakeAfterCertReq(sslSocket *ss, -+ CERTCertificate *cert, -+ SECKEYPrivateKey *key, -+ CERTCertificateList *certChain) -+{ -+ SECStatus rv = SECSuccess; -+ -+ /* XXX This code only works on the initial handshake on a connection, -+ ** XXX It does not work on a subsequent handshake (redo). -+ */ -+ if (ss->handshake != 0) { -+ ss->handshake = ssl_GatherRecord1stHandshake; -+ ss->ssl3.clientCertificate = cert; -+ ss->ssl3.clientPrivateKey = key; -+ ss->ssl3.clientCertChain = certChain; -+ if (!cert || !key || !certChain) { -+ /* we are missing the key, cert, or cert chain */ -+ if (ss->ssl3.clientCertificate) { -+ CERT_DestroyCertificate(ss->ssl3.clientCertificate); -+ ss->ssl3.clientCertificate = NULL; -+ } -+ if (ss->ssl3.clientPrivateKey) { -+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); -+ ss->ssl3.clientPrivateKey = NULL; -+ } -+ if (ss->ssl3.clientCertChain != NULL) { -+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain); -+ ss->ssl3.clientCertChain = NULL; -+ } -+ if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { -+ ss->ssl3.sendEmptyCert = PR_TRUE; -+ } else { -+ (void)SSL3_SendAlert(ss, alert_warning, no_certificate); -+ } -+ } -+ } else { -+ if (cert) { -+ CERT_DestroyCertificate(cert); -+ } -+ if (key) { -+ SECKEY_DestroyPrivateKey(key); -+ } -+ if (certChain) { -+ CERT_DestroyCertificateList(certChain); -+ } -+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); -+ rv = SECFailure; -+ } -+ return rv; -+} -+ - static SECStatus - ssl3_CheckFalseStart(sslSocket *ss) - { -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index 5f0e6c9..dad75b2 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -1702,16 +1702,16 @@ extern SECStatus ssl3_MasterSecretDeriveBypass(ssl3CipherSpec *pwSpec, - /* These functions are called from secnav, even though they're "private". */ - - extern int ssl2_SendErrorMessage(struct sslSocketStr *ss, int error); --extern int SSL_RestartHandshakeAfterCertReq(struct sslSocketStr *ss, -- CERTCertificate *cert, -- SECKEYPrivateKey *key, -- CERTCertificateList *certChain); - extern sslSocket *ssl_FindSocket(PRFileDesc *fd); - extern void ssl_FreeSocket(struct sslSocketStr *ssl); - extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, - SSL3AlertDescription desc); - extern SECStatus ssl3_DecodeError(sslSocket *ss); - -+extern SECStatus ssl3_RestartHandshakeAfterCertReq(struct sslSocketStr *ss, -+ CERTCertificate *cert, -+ SECKEYPrivateKey *key, -+ CERTCertificateList *certChain); - extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error); - - /* -diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c -index 5773748..a087ffc 100644 ---- a/lib/ssl/sslsecur.c -+++ b/lib/ssl/sslsecur.c -@@ -1535,17 +1535,70 @@ SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle) - return SECSuccess; - } - --/* DO NOT USE. This function was exported in ssl.def with the wrong signature; -- * this implementation exists to maintain link-time compatibility. -- */ --int --SSL_RestartHandshakeAfterCertReq(sslSocket *ss, -+/* -+ * attempt to restart the handshake after asynchronously handling -+ * a request for the client's certificate. -+ * -+ * inputs: -+ * cert Client cert chosen by application. -+ * Note: ssl takes this reference, and does not bump the -+ * reference count. The caller should drop its reference -+ * without calling CERT_DestroyCertificate after calling this -+ * function. -+ * -+ * key Private key associated with cert. This function takes -+ * ownership of the private key, so the caller should drop its -+ * reference without destroying the private key after this -+ * function returns. -+ * -+ * certChain Chain of signers for cert. -+ * Note: ssl takes this reference, and does not copy the chain. -+ * The caller should drop its reference without destroying the -+ * chain. SSL will free the chain when it is done with it. -+ * -+ * Return value: XXX -+ * -+ * XXX This code only works on the initial handshake on a connection, XXX -+ * It does not work on a subsequent handshake (redo). -+ */ -+SECStatus -+SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain) - { -- PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); -- return -1; -+ sslSocket *ss = ssl_FindSocket(fd); -+ SECStatus ret; -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterCertReq", -+ SSL_GETPID(), fd)); -+ if (cert) { -+ CERT_DestroyCertificate(cert); -+ } -+ if (key) { -+ SECKEY_DestroyPrivateKey(key); -+ } -+ if (certChain) { -+ CERT_DestroyCertificateList(certChain); -+ } -+ return SECFailure; -+ } -+ -+ ssl_Get1stHandshakeLock(ss); /************************************/ -+ -+ if (ss->version >= SSL_LIBRARY_VERSION_3_0) { -+ ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain); -+ } else { -+ if (certChain != NULL) { -+ CERT_DestroyCertificateList(certChain); -+ } -+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); -+ ret = SECFailure; -+ } -+ -+ ssl_Release1stHandshakeLock(ss); /************************************/ -+ return ret; - } - - /* DO NOT USE. This function was exported in ssl.def with the wrong signature;
diff --git a/net/third_party/nss/patches/secretexporterlocks.patch b/net/third_party/nss/patches/secretexporterlocks.patch deleted file mode 100644 index a95ef278..0000000 --- a/net/third_party/nss/patches/secretexporterlocks.patch +++ /dev/null
@@ -1,36 +0,0 @@ -diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c -index 527b1a4..c59879c 100644 ---- a/lib/ssl/sslinfo.c -+++ b/lib/ssl/sslinfo.c -@@ -406,8 +406,13 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, - return SECFailure; - } - -+ ssl_GetRecvBufLock(ss); -+ ssl_GetSSL3HandshakeLock(ss); -+ - if (ss->version < SSL_LIBRARY_VERSION_3_1_TLS) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION); -+ ssl_ReleaseSSL3HandshakeLock(ss); -+ ssl_ReleaseRecvBufLock(ss); - return SECFailure; - } - -@@ -418,6 +423,8 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, - } - val = PORT_Alloc(valLen); - if (!val) { -+ ssl_ReleaseSSL3HandshakeLock(ss); -+ ssl_ReleaseRecvBufLock(ss); - return SECFailure; - } - i = 0; -@@ -445,6 +452,8 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, - valLen, out, outLen); - } - ssl_ReleaseSpecReadLock(ss); -+ ssl_ReleaseSSL3HandshakeLock(ss); -+ ssl_ReleaseRecvBufLock(ss); - - PORT_ZFree(val, valLen); - return rv;
diff --git a/net/third_party/nss/patches/sessioncache.patch b/net/third_party/nss/patches/sessioncache.patch deleted file mode 100644 index 6e100c6..0000000 --- a/net/third_party/nss/patches/sessioncache.patch +++ /dev/null
@@ -1,90 +0,0 @@ -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index 70665a1..de5078b 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -973,6 +973,18 @@ SSL_IMPORT int SSL_DataPending(PRFileDesc *fd); - SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd); - - /* -+** Cache the SSL session associated with fd, if it has not already been cached. -+*/ -+SSL_IMPORT SECStatus SSL_CacheSession(PRFileDesc *fd); -+ -+/* -+** Cache the SSL session associated with fd, if it has not already been cached. -+** This function may only be called when processing within a callback assigned -+** via SSL_HandshakeCallback -+*/ -+SSL_IMPORT SECStatus SSL_CacheSessionUnlocked(PRFileDesc *fd); -+ -+/* - ** Return a SECItem containing the SSL session ID associated with the fd. - */ - SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd); -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index b100b9b..7649abe 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -12397,7 +12397,7 @@ ssl3_FinishHandshake(sslSocket *ss) - ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE; - } - -- if (ss->ssl3.hs.cacheSID) { -+ if (ss->ssl3.hs.cacheSID && ss->sec.isServer) { - PORT_Assert(ss->sec.ci.sid->cached == never_cached); - (*ss->sec.cache)(ss->sec.ci.sid); - ss->ssl3.hs.cacheSID = PR_FALSE; -diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c -index 7ff0a2c..129f1f3 100644 ---- a/lib/ssl/sslsecur.c -+++ b/lib/ssl/sslsecur.c -@@ -1486,6 +1486,49 @@ SSL_InvalidateSession(PRFileDesc *fd) - return rv; - } - -+static void -+ssl3_CacheSessionUnlocked(sslSocket *ss) -+{ -+ PORT_Assert(!ss->sec.isServer); -+ -+ if (ss->ssl3.hs.cacheSID) { -+ ss->sec.cache(ss->sec.ci.sid); -+ ss->ssl3.hs.cacheSID = PR_FALSE; -+ } -+} -+ -+SECStatus -+SSL_CacheSession(PRFileDesc *fd) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ SECStatus rv = SECFailure; -+ -+ if (ss) { -+ ssl_Get1stHandshakeLock(ss); -+ ssl_GetSSL3HandshakeLock(ss); -+ -+ ssl3_CacheSessionUnlocked(ss); -+ rv = SECSuccess; -+ -+ ssl_ReleaseSSL3HandshakeLock(ss); -+ ssl_Release1stHandshakeLock(ss); -+ } -+ return rv; -+} -+ -+SECStatus -+SSL_CacheSessionUnlocked(PRFileDesc *fd) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ SECStatus rv = SECFailure; -+ -+ if (ss) { -+ ssl3_CacheSessionUnlocked(ss); -+ rv = SECSuccess; -+ } -+ return rv; -+} -+ - SECItem * - SSL_GetSessionID(PRFileDesc *fd) - {
diff --git a/net/third_party/nss/patches/tlsunique.patch b/net/third_party/nss/patches/tlsunique.patch deleted file mode 100644 index d004ca7..0000000 --- a/net/third_party/nss/patches/tlsunique.patch +++ /dev/null
@@ -1,156 +0,0 @@ -diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h -index 870a8cc..3550580 100644 ---- a/lib/ssl/ssl.h -+++ b/lib/ssl/ssl.h -@@ -387,6 +387,27 @@ SSL_IMPORT SECStatus SSL_DHEGroupPrefSet(PRFileDesc *fd, - */ - SSL_IMPORT SECStatus SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled); - -+/* SSLChannelBindingType enumerates the types of supported channel binding -+ * values. See RFC 5929. */ -+typedef enum SSLChannelBindingType { -+ SSL_CHANNEL_BINDING_TLS_UNIQUE = 1, -+} SSLChannelBindingType; -+ -+/* SSL_GetChannelBinding copies the requested channel binding value, as defined -+ * in RFC 5929, into |out|. The full length of the binding value is written -+ * into |*outLen|. -+ * -+ * At most |outLenMax| bytes of data are copied. If |outLenMax| is -+ * insufficient then the function returns SECFailure and sets the error to -+ * SEC_ERROR_OUTPUT_LEN, but |*outLen| is still set. -+ * -+ * This call will fail if made during a renegotiation. */ -+SSL_IMPORT SECStatus SSL_GetChannelBinding(PRFileDesc *fd, -+ SSLChannelBindingType binding_type, -+ unsigned char *out, -+ unsigned int *outLen, -+ unsigned int outLenMax); -+ - /* SSL Version Range API - ** - ** This API should be used to control SSL 3.0 & TLS support instead of the -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c -index a2beec2..1394542 100644 ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -13808,6 +13808,69 @@ ssl3_InitSocketPolicy(sslSocket *ss) - ss->ssl3.signatureAlgorithmCount = PR_ARRAY_SIZE(defaultSignatureAlgorithms); - } - -+SECStatus -+ssl3_GetTLSUniqueChannelBinding(sslSocket *ss, -+ unsigned char *out, -+ unsigned int *outLen, -+ unsigned int outLenMax) -+{ -+ PRBool isTLS; -+ int index = 0; -+ unsigned int len; -+ SECStatus rv = SECFailure; -+ -+ *outLen = 0; -+ -+ ssl_GetSSL3HandshakeLock(ss); -+ -+ ssl_GetSpecReadLock(ss); -+ isTLS = (PRBool)(ss->ssl3.cwSpec->version > SSL_LIBRARY_VERSION_3_0); -+ ssl_ReleaseSpecReadLock(ss); -+ -+ /* The tls-unique channel binding is the first Finished structure in the -+ * handshake. In the case of a resumption, that's the server's Finished. -+ * Otherwise, it's the client's Finished. */ -+ len = ss->ssl3.hs.finishedBytes; -+ -+ /* Sending or receiving a Finished message will set finishedBytes to a -+ * non-zero value. */ -+ if (len == 0) { -+ PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); -+ goto loser; -+ } -+ -+ /* If we are in the middle of a renegotiation then the channel binding -+ * value is poorly defined and depends on the direction that it will be -+ * used on. Therefore we simply return an error in this case. */ -+ if (ss->firstHsDone && ss->ssl3.hs.ws != idle_handshake) { -+ PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); -+ goto loser; -+ } -+ -+ /* If resuming, then we want the second Finished value in the array, which -+ * is the server's */ -+ if (ss->ssl3.hs.isResuming) -+ index = 1; -+ -+ *outLen = len; -+ if (outLenMax < len) { -+ PORT_SetError(SEC_ERROR_OUTPUT_LEN); -+ goto loser; -+ } -+ -+ if (isTLS) { -+ memcpy(out, &ss->ssl3.hs.finishedMsgs.tFinished[index], len); -+ } else { -+ memcpy(out, &ss->ssl3.hs.finishedMsgs.sFinished[index], len); -+ } -+ -+ rv = SECSuccess; -+ -+loser: -+ ssl_ReleaseSSL3HandshakeLock(ss); -+ return rv; -+} -+ - /* ssl3_config_match_init must have already been called by - * the caller of this function. - */ -diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h -index 4607655..d47eb28 100644 ---- a/lib/ssl/sslimpl.h -+++ b/lib/ssl/sslimpl.h -@@ -1981,6 +1981,11 @@ extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, - extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data, - unsigned int length); - -+extern SECStatus ssl3_GetTLSUniqueChannelBinding(sslSocket *ss, -+ unsigned char *out, -+ unsigned int *outLen, -+ unsigned int outLenMax); -+ - /* Construct a new NSPR socket for the app to use */ - extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd); - extern void ssl_FreePRSocket(PRFileDesc *fd); -diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c -index 84c78b3..e312d82 100644 ---- a/lib/ssl/sslsock.c -+++ b/lib/ssl/sslsock.c -@@ -1700,6 +1700,29 @@ SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled) - return SECSuccess; - } - -+SECStatus -+SSL_GetChannelBinding(PRFileDesc *fd, -+ SSLChannelBindingType binding_type, -+ unsigned char *out, -+ unsigned int *outLen, -+ unsigned int outLenMax) -+{ -+ sslSocket *ss = ssl_FindSocket(fd); -+ -+ if (!ss) { -+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelBinding", -+ SSL_GETPID(), fd)); -+ return SECFailure; -+ } -+ -+ if (binding_type != SSL_CHANNEL_BINDING_TLS_UNIQUE) { -+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR); -+ return SECFailure; -+ } -+ -+ return ssl3_GetTLSUniqueChannelBinding(ss, out, outLen, outLenMax); -+} -+ - #include "dhe-param.c" - - static const SSLDHEGroupType ssl_default_dhe_groups[] = {
diff --git a/net/third_party/nss/ssl.gyp b/net/third_party/nss/ssl.gyp deleted file mode 100644 index 4abf713..0000000 --- a/net/third_party/nss/ssl.gyp +++ /dev/null
@@ -1,114 +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. - -{ - 'targets': [ - { - 'target_name': 'libssl', - 'type': '<(component)', - 'product_name': 'crssl', # Don't conflict with OpenSSL's libssl - 'sources': [ - 'ssl/SSLerrs.h', - 'ssl/authcert.c', - 'ssl/cmpcert.c', - 'ssl/derive.c', - 'ssl/dtlscon.c', - 'ssl/preenc.h', - 'ssl/prelib.c', - 'ssl/ssl.h', - 'ssl/ssl3con.c', - 'ssl/ssl3ecc.c', - 'ssl/ssl3ext.c', - 'ssl/ssl3gthr.c', - 'ssl/ssl3prot.h', - 'ssl/sslauth.c', - 'ssl/sslcon.c', - 'ssl/ssldef.c', - 'ssl/sslenum.c', - 'ssl/sslerr.c', - 'ssl/sslerr.h', - 'ssl/sslerrstrs.c', - 'ssl/sslgathr.c', - 'ssl/sslimpl.h', - 'ssl/sslinfo.c', - 'ssl/sslinit.c', - 'ssl/sslmutex.c', - 'ssl/sslmutex.h', - 'ssl/sslnonce.c', - 'ssl/sslproto.h', - 'ssl/sslreveal.c', - 'ssl/sslsecur.c', - 'ssl/sslsnce.c', - 'ssl/sslsock.c', - 'ssl/sslt.h', - 'ssl/ssltrace.c', - 'ssl/sslver.c', - 'ssl/tls13con.c', - 'ssl/tls13con.h', - 'ssl/tls13hkdf.c', - 'ssl/tls13hkdf.h', - 'ssl/unix_err.c', - 'ssl/unix_err.h', - ], - 'defines': [ - 'NO_PKCS11_BYPASS', - 'NSS_ENABLE_ECC', - 'USE_UTIL_DIRECTLY', - ], - 'variables': { - 'clang_warning_flags_unset': [ - # ssl uses PR_ASSERT(!"foo") instead of PR_ASSERT(false && "foo") - '-Wstring-conversion', - ], - }, - 'conditions': [ - ['component == "shared_library"', { - 'conditions': [ - ['OS == "ios"', { - 'xcode_settings': { - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'NO', - }, - }], - ], - }], - [ 'clang == 1', { - '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', - ], - }], - [ 'OS == "ios"', { - 'defines': [ - 'XP_UNIX', - 'DARWIN', - 'XP_MACOSX', - ], - }], - [ 'OS == "ios"', { - 'dependencies': [ - '../../../third_party/nss/nss.gyp:nspr', - '../../../third_party/nss/nss.gyp:nss', - ], - 'export_dependent_settings': [ - '../../../third_party/nss/nss.gyp:nspr', - '../../../third_party/nss/nss.gyp:nss', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - 'ssl', - ], - }, - }], - ], - 'configurations': { - 'Debug_Base': { - 'defines': [ - 'DEBUG', - ], - }, - }, - }, - ], -}
diff --git a/net/third_party/nss/ssl/BUILD.gn b/net/third_party/nss/ssl/BUILD.gn deleted file mode 100644 index 06a113d2..0000000 --- a/net/third_party/nss/ssl/BUILD.gn +++ /dev/null
@@ -1,105 +0,0 @@ -# Copyright (c) 2013 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. - -config("ssl_config") { - include_dirs = [ "." ] - - if (is_mac || is_win) { - defines = [ "NSS_PLATFORM_CLIENT_AUTH" ] - } -} - -component("libssl") { - output_name = "crssl" - - sources = [ - "SSLerrs.h", - "authcert.c", - "cmpcert.c", - "derive.c", - "dtlscon.c", - "preenc.h", - "prelib.c", - "ssl.h", - "ssl3con.c", - "ssl3ecc.c", - "ssl3ext.c", - "ssl3gthr.c", - "ssl3prot.h", - "sslauth.c", - "sslcon.c", - "ssldef.c", - "sslenum.c", - "sslerr.c", - "sslerr.h", - "sslerrstrs.c", - "sslgathr.c", - "sslimpl.h", - "sslinfo.c", - "sslinit.c", - "sslmutex.c", - "sslmutex.h", - "sslnonce.c", - "sslproto.h", - "sslreveal.c", - "sslsecur.c", - "sslsnce.c", - "sslsock.c", - "sslt.h", - "ssltrace.c", - "sslver.c", - "tls13con.c", - "tls13con.h", - "tls13hkdf.c", - "tls13hkdf.h", - "unix_err.c", - "unix_err.h", - ] - - public_configs = [ ":ssl_config" ] - - cflags = [] - defines = [ - "NO_PKCS11_BYPASS", - "NSS_ENABLE_ECC", - "USE_UTIL_DIRECTLY", - ] - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] - - if (is_clang) { - # SSL triggers some of these Clang warnings. - configs -= [ "//build/config/clang:extra_warnings" ] - - # 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" ] - - if (is_ios) { - # libssl uses routines deprecated on iOS (sem_init/sem_destroy). - # https://bugzilla.mozilla.org/show_bug.cgi?id=1192500 - cflags += [ "-Wno-deprecated-declarations" ] - } - } - - if (is_ios) { - defines += [ - "XP_UNIX", - "DARWIN", - "XP_MACOSX", - ] - } - - if (is_ios) { - public_deps = [ - "//third_party/nss:nspr", - "//third_party/nss:nss", - ] - } - - if (is_debug) { - defines += [ "DEBUG" ] - } -}
diff --git a/net/third_party/nss/ssl/Makefile b/net/third_party/nss/ssl/Makefile deleted file mode 100644 index d56cbf2..0000000 --- a/net/third_party/nss/ssl/Makefile +++ /dev/null
@@ -1,63 +0,0 @@ -#! gmake -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -####################################################################### -# (1) Include initial platform-independent assignments (MANDATORY). # -####################################################################### - -include manifest.mn - -####################################################################### -# (2) Include "global" configuration information. (OPTIONAL) # -####################################################################### - -include $(CORE_DEPTH)/coreconf/config.mk - -####################################################################### -# (3) Include "component" configuration information. (OPTIONAL) # -####################################################################### - - - -####################################################################### -# (4) Include "local" platform-dependent assignments (OPTIONAL). # -####################################################################### - -include config.mk - -ifeq (,$(filter-out WIN%,$(OS_TARGET))) -CSRCS += win32err.c -DEFINES += -DIN_LIBSSL -else -ifeq ($(OS_TARGET),OS2) -CSRCS += os2_err.c -else -CSRCS += unix_err.c -endif -endif - -####################################################################### -# (5) Execute "global" rules. (OPTIONAL) # -####################################################################### - -include $(CORE_DEPTH)/coreconf/rules.mk - -####################################################################### -# (6) Execute "component" rules. (OPTIONAL) # -####################################################################### - - - -####################################################################### -# (7) Execute "local" rules. (OPTIONAL). # -####################################################################### - -export:: private_export - -ifndef NSS_NO_PKCS11_BYPASS -# indicates dependency on freebl static lib -$(SHARED_LIBRARY): $(CRYPTOLIB) -endif
diff --git a/net/third_party/nss/ssl/SSLerrs.h b/net/third_party/nss/ssl/SSLerrs.h deleted file mode 100644 index 555e629..0000000 --- a/net/third_party/nss/ssl/SSLerrs.h +++ /dev/null
@@ -1,476 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* SSL-specific security error codes */ -/* caller must include "sslerr.h" */ - -ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0, - "Unable to communicate securely. Peer does not support high-grade encryption.") - -ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1, - "Unable to communicate securely. Peer requires high-grade encryption which is not supported.") - -ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2, - "Cannot communicate securely with peer: no common encryption algorithm(s).") - -ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, - "Unable to find the certificate or key necessary for authentication.") - -ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4, - "Unable to communicate securely with peer: peers's certificate was rejected.") - -ER3(SSL_ERROR_UNUSED_5, SSL_ERROR_BASE + 5, - "Unrecognized SSL error code.") - -ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, - "The server has encountered bad data from the client.") - -ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7, - "The client has encountered bad data from the server.") - -ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, - "Unsupported certificate type.") - -ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, - "Peer using unsupported version of security protocol.") - -ER3(SSL_ERROR_UNUSED_10, SSL_ERROR_BASE + 10, - "Unrecognized SSL error code.") - -ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, - "Client authentication failed: private key in key database does not match public key in certificate database.") - -ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12, - "Unable to communicate securely with peer: requested domain name does not match the server's certificate.") - -ER3(SSL_ERROR_POST_WARNING, SSL_ERROR_BASE + 13, - "Unrecognized SSL error code.") - -ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), - "Peer only supports SSL version 2, which is locally disabled.") - -ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15), - "SSL received a record with an incorrect Message Authentication Code.") - -ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16), - "SSL peer reports incorrect Message Authentication Code.") - -ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17), - "SSL peer cannot verify your certificate.") - -ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18), - "SSL peer rejected your certificate as revoked.") - -ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19), - "SSL peer rejected your certificate as expired.") - -ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), - "Cannot connect: SSL is disabled.") - -ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21), - "Cannot connect: SSL peer is in another FORTEZZA domain.") - -ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE, (SSL_ERROR_BASE + 22), - "An unknown SSL cipher suite has been requested.") - -ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED, (SSL_ERROR_BASE + 23), - "No cipher suites are present and enabled in this program.") - -ER3(SSL_ERROR_BAD_BLOCK_PADDING, (SSL_ERROR_BASE + 24), - "SSL received a record with bad block padding.") - -ER3(SSL_ERROR_RX_RECORD_TOO_LONG, (SSL_ERROR_BASE + 25), - "SSL received a record that exceeded the maximum permissible length.") - -ER3(SSL_ERROR_TX_RECORD_TOO_LONG, (SSL_ERROR_BASE + 26), - "SSL attempted to send a record that exceeded the maximum permissible length.") - -/* - * Received a malformed (too long or short or invalid content) SSL handshake. - */ -ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST, (SSL_ERROR_BASE + 27), - "SSL received a malformed Hello Request handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, (SSL_ERROR_BASE + 28), - "SSL received a malformed Client Hello handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, (SSL_ERROR_BASE + 29), - "SSL received a malformed Server Hello handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE, (SSL_ERROR_BASE + 30), - "SSL received a malformed Certificate handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH, (SSL_ERROR_BASE + 31), - "SSL received a malformed Server Key Exchange handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST, (SSL_ERROR_BASE + 32), - "SSL received a malformed Certificate Request handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE, (SSL_ERROR_BASE + 33), - "SSL received a malformed Server Hello Done handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY, (SSL_ERROR_BASE + 34), - "SSL received a malformed Certificate Verify handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH, (SSL_ERROR_BASE + 35), - "SSL received a malformed Client Key Exchange handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_FINISHED, (SSL_ERROR_BASE + 36), - "SSL received a malformed Finished handshake message.") - -/* - * Received a malformed (too long or short) SSL record. - */ -ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER, (SSL_ERROR_BASE + 37), - "SSL received a malformed Change Cipher Spec record.") - -ER3(SSL_ERROR_RX_MALFORMED_ALERT, (SSL_ERROR_BASE + 38), - "SSL received a malformed Alert record.") - -ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE, (SSL_ERROR_BASE + 39), - "SSL received a malformed Handshake record.") - -ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA, (SSL_ERROR_BASE + 40), - "SSL received a malformed Application Data record.") - -/* - * Received an SSL handshake that was inappropriate for the state we're in. - * E.g. Server received message from server, or wrong state in state machine. - */ -ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST, (SSL_ERROR_BASE + 41), - "SSL received an unexpected Hello Request handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO, (SSL_ERROR_BASE + 42), - "SSL received an unexpected Client Hello handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO, (SSL_ERROR_BASE + 43), - "SSL received an unexpected Server Hello handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE, (SSL_ERROR_BASE + 44), - "SSL received an unexpected Certificate handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH, (SSL_ERROR_BASE + 45), - "SSL received an unexpected Server Key Exchange handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, (SSL_ERROR_BASE + 46), - "SSL received an unexpected Certificate Request handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE, (SSL_ERROR_BASE + 47), - "SSL received an unexpected Server Hello Done handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY, (SSL_ERROR_BASE + 48), - "SSL received an unexpected Certificate Verify handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH, (SSL_ERROR_BASE + 49), - "SSL received an unexpected Client Key Exchange handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED, (SSL_ERROR_BASE + 50), - "SSL received an unexpected Finished handshake message.") - -/* - * Received an SSL record that was inappropriate for the state we're in. - */ -ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER, (SSL_ERROR_BASE + 51), - "SSL received an unexpected Change Cipher Spec record.") - -ER3(SSL_ERROR_RX_UNEXPECTED_ALERT, (SSL_ERROR_BASE + 52), - "SSL received an unexpected Alert record.") - -ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE, (SSL_ERROR_BASE + 53), - "SSL received an unexpected Handshake record.") - -ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54), - "SSL received an unexpected Application Data record.") - -/* - * Received record/message with unknown discriminant. - */ -ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, (SSL_ERROR_BASE + 55), - "SSL received a record with an unknown content type.") - -ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE, (SSL_ERROR_BASE + 56), - "SSL received a handshake message with an unknown message type.") - -ER3(SSL_ERROR_RX_UNKNOWN_ALERT, (SSL_ERROR_BASE + 57), - "SSL received an alert record with an unknown alert description.") - -/* - * Received an alert reporting what we did wrong. (more alerts above) - */ -ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT, (SSL_ERROR_BASE + 58), - "SSL peer has closed this connection.") - -ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, (SSL_ERROR_BASE + 59), - "SSL peer was not expecting a handshake message it received.") - -ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT, (SSL_ERROR_BASE + 60), - "SSL peer was unable to successfully decompress an SSL record it received.") - -ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT, (SSL_ERROR_BASE + 61), - "SSL peer was unable to negotiate an acceptable set of security parameters.") - -ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, (SSL_ERROR_BASE + 62), - "SSL peer rejected a handshake message for unacceptable content.") - -ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT, (SSL_ERROR_BASE + 63), - "SSL peer does not support certificates of the type it received.") - -ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT, (SSL_ERROR_BASE + 64), - "SSL peer had some unspecified issue with the certificate it received.") - -ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE, (SSL_ERROR_BASE + 65), - "SSL experienced a failure of its random number generator.") - -ER3(SSL_ERROR_SIGN_HASHES_FAILURE, (SSL_ERROR_BASE + 66), - "Unable to digitally sign data required to verify your certificate.") - -ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE, (SSL_ERROR_BASE + 67), - "SSL was unable to extract the public key from the peer's certificate.") - -ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE, (SSL_ERROR_BASE + 68), - "Unspecified failure while processing SSL Server Key Exchange handshake.") - -ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE, (SSL_ERROR_BASE + 69), - "Unspecified failure while processing SSL Client Key Exchange handshake.") - -ER3(SSL_ERROR_ENCRYPTION_FAILURE, (SSL_ERROR_BASE + 70), - "Bulk data encryption algorithm failed in selected cipher suite.") - -ER3(SSL_ERROR_DECRYPTION_FAILURE, (SSL_ERROR_BASE + 71), - "Bulk data decryption algorithm failed in selected cipher suite.") - -ER3(SSL_ERROR_SOCKET_WRITE_FAILURE, (SSL_ERROR_BASE + 72), - "Attempt to write encrypted data to underlying socket failed.") - -ER3(SSL_ERROR_MD5_DIGEST_FAILURE, (SSL_ERROR_BASE + 73), - "MD5 digest function failed.") - -ER3(SSL_ERROR_SHA_DIGEST_FAILURE, (SSL_ERROR_BASE + 74), - "SHA-1 digest function failed.") - -ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE, (SSL_ERROR_BASE + 75), - "MAC computation failed.") - -ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE, (SSL_ERROR_BASE + 76), - "Failure to create Symmetric Key context.") - -ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE, (SSL_ERROR_BASE + 77), - "Failure to unwrap the Symmetric key in Client Key Exchange message.") - -ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED, (SSL_ERROR_BASE + 78), - "SSL Server attempted to use domestic-grade public key with export cipher suite.") - -ER3(SSL_ERROR_IV_PARAM_FAILURE, (SSL_ERROR_BASE + 79), - "PKCS11 code failed to translate an IV into a param.") - -ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, (SSL_ERROR_BASE + 80), - "Failed to initialize the selected cipher suite.") - -ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE, (SSL_ERROR_BASE + 81), - "Client failed to generate session keys for SSL session.") - -ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG, (SSL_ERROR_BASE + 82), - "Server has no key for the attempted key exchange algorithm.") - -ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL, (SSL_ERROR_BASE + 83), - "PKCS#11 token was inserted or removed while operation was in progress.") - -ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND, (SSL_ERROR_BASE + 84), - "No PKCS#11 token could be found to do a required operation.") - -ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP, (SSL_ERROR_BASE + 85), - "Cannot communicate securely with peer: no common compression algorithm(s).") - -ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED, (SSL_ERROR_BASE + 86), - "Cannot perform the operation until the handshake is complete.") - -ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE, (SSL_ERROR_BASE + 87), - "Received incorrect handshakes hash values from peer.") - -ER3(SSL_ERROR_CERT_KEA_MISMATCH, (SSL_ERROR_BASE + 88), - "The certificate provided cannot be used with the selected key exchange algorithm.") - -ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA, (SSL_ERROR_BASE + 89), - "No certificate authority is trusted for SSL client authentication.") - -ER3(SSL_ERROR_SESSION_NOT_FOUND, (SSL_ERROR_BASE + 90), - "Client's SSL session ID not found in server's session cache.") - -ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT, (SSL_ERROR_BASE + 91), - "Peer was unable to decrypt an SSL record it received.") - -ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT, (SSL_ERROR_BASE + 92), - "Peer received an SSL record that was longer than is permitted.") - -ER3(SSL_ERROR_UNKNOWN_CA_ALERT, (SSL_ERROR_BASE + 93), - "Peer does not recognize and trust the CA that issued your certificate.") - -ER3(SSL_ERROR_ACCESS_DENIED_ALERT, (SSL_ERROR_BASE + 94), - "Peer received a valid certificate, but access was denied.") - -ER3(SSL_ERROR_DECODE_ERROR_ALERT, (SSL_ERROR_BASE + 95), - "Peer could not decode an SSL handshake message.") - -ER3(SSL_ERROR_DECRYPT_ERROR_ALERT, (SSL_ERROR_BASE + 96), - "Peer reports failure of signature verification or key exchange.") - -ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT, (SSL_ERROR_BASE + 97), - "Peer reports negotiation not in compliance with export regulations.") - -ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT, (SSL_ERROR_BASE + 98), - "Peer reports incompatible or unsupported protocol version.") - -ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT, (SSL_ERROR_BASE + 99), - "Server requires ciphers more secure than those supported by client.") - -ER3(SSL_ERROR_INTERNAL_ERROR_ALERT, (SSL_ERROR_BASE + 100), - "Peer reports it experienced an internal error.") - -ER3(SSL_ERROR_USER_CANCELED_ALERT, (SSL_ERROR_BASE + 101), - "Peer user canceled handshake.") - -ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT, (SSL_ERROR_BASE + 102), - "Peer does not permit renegotiation of SSL security parameters.") - -ER3(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED, (SSL_ERROR_BASE + 103), - "SSL server cache not configured and not disabled for this socket.") - -ER3(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT, (SSL_ERROR_BASE + 104), - "SSL peer does not support requested TLS hello extension.") - -ER3(SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT, (SSL_ERROR_BASE + 105), - "SSL peer could not obtain your certificate from the supplied URL.") - -ER3(SSL_ERROR_UNRECOGNIZED_NAME_ALERT, (SSL_ERROR_BASE + 106), - "SSL peer has no certificate for the requested DNS name.") - -ER3(SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT, (SSL_ERROR_BASE + 107), - "SSL peer was unable to get an OCSP response for its certificate.") - -ER3(SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT, (SSL_ERROR_BASE + 108), - "SSL peer reported bad certificate hash value.") - -ER3(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 109), - "SSL received an unexpected New Session Ticket handshake message.") - -ER3(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 110), - "SSL received a malformed New Session Ticket handshake message.") - -ER3(SSL_ERROR_DECOMPRESSION_FAILURE, (SSL_ERROR_BASE + 111), - "SSL received a compressed record that could not be decompressed.") - -ER3(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, (SSL_ERROR_BASE + 112), - "Renegotiation is not allowed on this SSL socket.") - -ER3(SSL_ERROR_UNSAFE_NEGOTIATION, (SSL_ERROR_BASE + 113), - "Peer attempted old style (potentially vulnerable) handshake.") - -ER3(SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD, (SSL_ERROR_BASE + 114), - "SSL received an unexpected uncompressed record.") - -ER3(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY, (SSL_ERROR_BASE + 115), - "SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.") - -ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116), - "SSL received invalid NPN extension data.") - -ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2, (SSL_ERROR_BASE + 117), - "SSL feature not supported for SSL 2.0 connections.") - -ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS, (SSL_ERROR_BASE + 118), - "SSL feature not supported for servers.") - -ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS, (SSL_ERROR_BASE + 119), - "SSL feature not supported for clients.") - -ER3(SSL_ERROR_INVALID_VERSION_RANGE, (SSL_ERROR_BASE + 120), - "SSL version range is not valid.") - -ER3(SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 121), - "SSL peer selected a cipher suite disallowed for the selected protocol version.") - -ER3(SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 122), - "SSL received a malformed Hello Verify Request handshake message.") - -ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 123), - "SSL received an unexpected Hello Verify Request handshake message.") - -ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, (SSL_ERROR_BASE + 124), - "SSL feature not supported for the protocol version.") - -ER3(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS, (SSL_ERROR_BASE + 125), - "SSL received an unexpected Certificate Status handshake message.") - -ER3(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, (SSL_ERROR_BASE + 126), - "Unsupported hash algorithm used by TLS peer.") - -ER3(SSL_ERROR_DIGEST_FAILURE, (SSL_ERROR_BASE + 127), - "Digest function failed.") - -ER3(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 128), - "Incorrect signature algorithm specified in a digitally-signed element.") - -ER3(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK, (SSL_ERROR_BASE + 129), - "The next protocol negotiation extension was enabled, but the callback was cleared prior to being needed.") - -ER3(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL, (SSL_ERROR_BASE + 130), - "The server supports no protocols that the client advertises in the ALPN extension.") - -ER3(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, (SSL_ERROR_BASE + 131), - "The server rejected the handshake because the client downgraded to a lower " - "TLS version than the server supports.") - -ER3(SSL_ERROR_WEAK_SERVER_CERT_KEY, (SSL_ERROR_BASE + 132), - "The server certificate included a public key that was too weak.") - -ER3(SSL_ERROR_RX_SHORT_DTLS_READ, (SSL_ERROR_BASE + 133), - "Not enough room in buffer for DTLS record.") - -ER3(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 134), - "No supported TLS signature algorithm was configured.") - -ER3(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 135), - "The peer used an unsupported combination of signature and hash algorithm.") - -ER3(SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET, (SSL_ERROR_BASE + 136), - "The peer tried to resume without a correct extended_master_secret extension") - -ER3(SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET, (SSL_ERROR_BASE + 137), - "The peer tried to resume with an unexpected extended_master_secret extension") - -ER3(SSL_ERROR_RX_MALFORMED_KEY_SHARE, (SSL_ERROR_BASE + 138), - "SSL received a malformed Key Share extension.") - -ER3(SSL_ERROR_MISSING_KEY_SHARE, (SSL_ERROR_BASE + 139), - "SSL expected a Key Share extension.") - -ER3(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE, (SSL_ERROR_BASE + 140), - "SSL received a malformed ECDHE key share handshake extension.") - -ER3(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE, (SSL_ERROR_BASE + 141), - "SSL received a malformed DHE key share handshake extension.") - -ER3(SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS, (SSL_ERROR_BASE + 142), - "SSL received an unexpected Encrypted Extensions handshake message.") - -ER3(SSL_ERROR_MISSING_EXTENSION_ALERT, (SSL_ERROR_BASE + 143), - "SSL received a missing_extenson alert.") - -ER3(SSL_ERROR_KEY_EXCHANGE_FAILURE, (SSL_ERROR_BASE + 144), - "SSL had an error performing key exchange.") - -ER3(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 145), - "SSL received an extension that is not permitted for this version.") - -ER3(SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS, (SSL_ERROR_BASE + 146), - "SSL received a malformed Encrypted Extensions handshake message.") - -ER3(SSL_ERROR_BAD_CHANNEL_ID_DATA, (SSL_ERROR_BASE + 147), - "SSL received a malformed TLS Channel ID extension.") - -ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 148), - "The application provided an invalid TLS Channel ID key.") - -ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 149), - "The application could not get a TLS Channel ID.")
diff --git a/net/third_party/nss/ssl/authcert.c b/net/third_party/nss/ssl/authcert.c deleted file mode 100644 index 88c7c084..0000000 --- a/net/third_party/nss/ssl/authcert.c +++ /dev/null
@@ -1,89 +0,0 @@ -/* - * NSS utility functions - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <stdio.h> -#include <string.h> -#include "prerror.h" -#include "secitem.h" -#include "prnetdb.h" -#include "cert.h" -#include "nspr.h" -#include "secder.h" -#include "key.h" -#include "nss.h" -#include "ssl.h" -#include "pk11func.h" /* for PK11_ function calls */ - -/* - * This callback used by SSL to pull client sertificate upon - * server request - */ -SECStatus -NSS_GetClientAuthData(void *arg, - PRFileDesc *socket, - struct CERTDistNamesStr *caNames, - struct CERTCertificateStr **pRetCert, - struct SECKEYPrivateKeyStr **pRetKey) -{ - CERTCertificate *cert = NULL; - SECKEYPrivateKey *privkey = NULL; - char *chosenNickName = (char *)arg; /* CONST */ - void *proto_win = NULL; - SECStatus rv = SECFailure; - - proto_win = SSL_RevealPinArg(socket); - - if (chosenNickName) { - cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), - chosenNickName, certUsageSSLClient, - PR_FALSE, proto_win); - if (cert) { - privkey = PK11_FindKeyByAnyCert(cert, proto_win); - if (privkey) { - rv = SECSuccess; - } else { - CERT_DestroyCertificate(cert); - } - } - } else { /* no name given, automatically find the right cert. */ - CERTCertNicknames *names; - int i; - - names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), - SEC_CERT_NICKNAMES_USER, proto_win); - if (names != NULL) { - for (i = 0; i < names->numnicknames; i++) { - cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), - names->nicknames[i], certUsageSSLClient, - PR_FALSE, proto_win); - if (!cert) - continue; - /* Only check unexpired certs */ - if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != - secCertTimeValid) { - CERT_DestroyCertificate(cert); - continue; - } - rv = NSS_CmpCertChainWCANames(cert, caNames); - if (rv == SECSuccess) { - privkey = - PK11_FindKeyByAnyCert(cert, proto_win); - if (privkey) - break; - } - rv = SECFailure; - CERT_DestroyCertificate(cert); - } - CERT_FreeNicknames(names); - } - } - if (rv == SECSuccess) { - *pRetCert = cert; - *pRetKey = privkey; - } - return rv; -}
diff --git a/net/third_party/nss/ssl/derive.c b/net/third_party/nss/ssl/derive.c deleted file mode 100644 index 026dbd2..0000000 --- a/net/third_party/nss/ssl/derive.c +++ /dev/null
@@ -1,896 +0,0 @@ -/* - * Key Derivation that doesn't use PKCS11 - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ssl.h" /* prereq to sslimpl.h */ -#include "certt.h" /* prereq to sslimpl.h */ -#include "keythi.h" /* prereq to sslimpl.h */ -#include "sslimpl.h" -#ifndef NO_PKCS11_BYPASS -#include "blapi.h" -#endif - -#include "keyhi.h" -#include "pk11func.h" -#include "secasn1.h" -#include "cert.h" -#include "secmodt.h" - -#include "sslproto.h" -#include "sslerr.h" - -#ifndef NO_PKCS11_BYPASS -/* make this a macro! */ -#ifdef NOT_A_MACRO -static void -buildSSLKey(unsigned char *keyBlock, unsigned int keyLen, SECItem *result, - const char *label) -{ - result->type = siBuffer; - result->data = keyBlock; - result->len = keyLen; - PRINT_BUF(100, (NULL, label, keyBlock, keyLen)); -} -#else -#define buildSSLKey(keyBlock, keyLen, result, label) \ - { \ - (result)->type = siBuffer; \ - (result)->data = keyBlock; \ - (result)->len = keyLen; \ - PRINT_BUF(100, (NULL, label, keyBlock, keyLen)); \ - } -#endif - -/* - * SSL Key generation given pre master secret - */ -#ifndef NUM_MIXERS -#define NUM_MIXERS 9 -#endif -static const char *const mixers[NUM_MIXERS] = { - "A", - "BB", - "CCC", - "DDDD", - "EEEEE", - "FFFFFF", - "GGGGGGG", - "HHHHHHHH", - "IIIIIIIII" -}; - -SECStatus -ssl3_KeyAndMacDeriveBypass( - ssl3CipherSpec *pwSpec, - const unsigned char *cr, - const unsigned char *sr, - PRBool isTLS, - PRBool isExport) -{ - const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; - unsigned char *key_block = pwSpec->key_block; - unsigned char *key_block2 = NULL; - unsigned int block_bytes = 0; - unsigned int block_needed = 0; - unsigned int i; - unsigned int keySize; /* actual size of cipher keys */ - unsigned int effKeySize; /* effective size of cipher keys */ - unsigned int macSize; /* size of MAC secret */ - unsigned int IVSize; /* size of IV */ - PRBool explicitIV = PR_FALSE; - SECStatus rv = SECFailure; - SECStatus status = SECSuccess; - PRBool isFIPS = PR_FALSE; - PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2; - - SECItem srcr; - SECItem crsr; - - unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; - unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; - PRUint64 md5buf[22]; - PRUint64 shabuf[40]; - -#define md5Ctx ((MD5Context *)md5buf) -#define shaCtx ((SHA1Context *)shabuf) - - static const SECItem zed = { siBuffer, NULL, 0 }; - - if (pwSpec->msItem.data == NULL || - pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return rv; - } - - PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, - pwSpec->msItem.len)); - - /* figure out how much is needed */ - macSize = pwSpec->mac_size; - keySize = cipher_def->key_size; - effKeySize = cipher_def->secret_key_size; - IVSize = cipher_def->iv_size; - if (keySize == 0) { - effKeySize = IVSize = 0; /* only MACing */ - } - if (cipher_def->type == type_block && - pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { - /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */ - explicitIV = PR_TRUE; - } - block_needed = - 2 * (macSize + effKeySize + ((!isExport && !explicitIV) * IVSize)); - - /* - * clear out our returned keys so we can recover on failure - */ - pwSpec->client.write_key_item = zed; - pwSpec->client.write_mac_key_item = zed; - pwSpec->server.write_key_item = zed; - pwSpec->server.write_mac_key_item = zed; - - /* initialize the server random, client random block */ - srcr.type = siBuffer; - srcr.data = srcrdata; - srcr.len = sizeof srcrdata; - PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH); - PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH); - - /* initialize the client random, server random block */ - crsr.type = siBuffer; - crsr.data = crsrdata; - crsr.len = sizeof crsrdata; - PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); - PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); - PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len)); - - /* - * generate the key material: - */ - if (isTLS) { - SECItem keyblk; - - keyblk.type = siBuffer; - keyblk.data = key_block; - keyblk.len = block_needed; - - if (isTLS12) { - status = TLS_P_hash(HASH_AlgSHA256, &pwSpec->msItem, - "key expansion", &srcr, &keyblk, isFIPS); - } else { - status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk, - isFIPS); - } - if (status != SECSuccess) { - goto key_and_mac_derive_fail; - } - block_bytes = keyblk.len; - } else { - /* key_block = - * MD5(master_secret + SHA('A' + master_secret + - * ServerHello.random + ClientHello.random)) + - * MD5(master_secret + SHA('BB' + master_secret + - * ServerHello.random + ClientHello.random)) + - * MD5(master_secret + SHA('CCC' + master_secret + - * ServerHello.random + ClientHello.random)) + - * [...]; - */ - unsigned int made = 0; - for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) { - unsigned int outLen; - unsigned char sha_out[SHA1_LENGTH]; - - SHA1_Begin(shaCtx); - SHA1_Update(shaCtx, (unsigned char *)(mixers[i]), i + 1); - SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len); - SHA1_Update(shaCtx, srcr.data, srcr.len); - SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); - PORT_Assert(outLen == SHA1_LENGTH); - - MD5_Begin(md5Ctx); - MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len); - MD5_Update(md5Ctx, sha_out, outLen); - MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); - PORT_Assert(outLen == MD5_LENGTH); - made += MD5_LENGTH; - } - block_bytes = made; - } - PORT_Assert(block_bytes >= block_needed); - PORT_Assert(block_bytes <= sizeof pwSpec->key_block); - PRINT_BUF(100, (NULL, "key block", key_block, block_bytes)); - - /* - * Put the key material where it goes. - */ - key_block2 = key_block + block_bytes; - i = 0; /* now shows how much consumed */ - - /* - * The key_block is partitioned as follows: - * client_write_MAC_secret[CipherSpec.hash_size] - */ - buildSSLKey(&key_block[i], macSize, &pwSpec->client.write_mac_key_item, - "Client Write MAC Secret"); - i += macSize; - - /* - * server_write_MAC_secret[CipherSpec.hash_size] - */ - buildSSLKey(&key_block[i], macSize, &pwSpec->server.write_mac_key_item, - "Server Write MAC Secret"); - i += macSize; - - if (!keySize) { - /* only MACing */ - buildSSLKey(NULL, 0, &pwSpec->client.write_key_item, - "Client Write Key (MAC only)"); - buildSSLKey(NULL, 0, &pwSpec->server.write_key_item, - "Server Write Key (MAC only)"); - buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item, - "Client Write IV (MAC only)"); - buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item, - "Server Write IV (MAC only)"); - } else if (!isExport) { - /* - ** Generate Domestic write keys and IVs. - ** client_write_key[CipherSpec.key_material] - */ - buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item, - "Domestic Client Write Key"); - i += keySize; - - /* - ** server_write_key[CipherSpec.key_material] - */ - buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item, - "Domestic Server Write Key"); - i += keySize; - - if (IVSize > 0) { - if (explicitIV) { - static unsigned char zero_block[32]; - PORT_Assert(IVSize <= sizeof zero_block); - buildSSLKey(&zero_block[0], IVSize, - &pwSpec->client.write_iv_item, - "Domestic Client Write IV"); - buildSSLKey(&zero_block[0], IVSize, - &pwSpec->server.write_iv_item, - "Domestic Server Write IV"); - } else { - /* - ** client_write_IV[CipherSpec.IV_size] - */ - buildSSLKey(&key_block[i], IVSize, - &pwSpec->client.write_iv_item, - "Domestic Client Write IV"); - i += IVSize; - - /* - ** server_write_IV[CipherSpec.IV_size] - */ - buildSSLKey(&key_block[i], IVSize, - &pwSpec->server.write_iv_item, - "Domestic Server Write IV"); - i += IVSize; - } - } - PORT_Assert(i <= block_bytes); - } else if (!isTLS) { - /* - ** Generate SSL3 Export write keys and IVs. - */ - unsigned int outLen; - - /* - ** client_write_key[CipherSpec.key_material] - ** final_client_write_key = MD5(client_write_key + - ** ClientHello.random + ServerHello.random); - */ - MD5_Begin(md5Ctx); - MD5_Update(md5Ctx, &key_block[i], effKeySize); - MD5_Update(md5Ctx, crsr.data, crsr.len); - MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); - i += effKeySize; - buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, - "SSL3 Export Client Write Key"); - key_block2 += keySize; - - /* - ** server_write_key[CipherSpec.key_material] - ** final_server_write_key = MD5(server_write_key + - ** ServerHello.random + ClientHello.random); - */ - MD5_Begin(md5Ctx); - MD5_Update(md5Ctx, &key_block[i], effKeySize); - MD5_Update(md5Ctx, srcr.data, srcr.len); - MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); - i += effKeySize; - buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, - "SSL3 Export Server Write Key"); - key_block2 += keySize; - PORT_Assert(i <= block_bytes); - - if (IVSize) { - /* - ** client_write_IV = - ** MD5(ClientHello.random + ServerHello.random); - */ - MD5_Begin(md5Ctx); - MD5_Update(md5Ctx, crsr.data, crsr.len); - MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); - buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item, - "SSL3 Export Client Write IV"); - key_block2 += IVSize; - - /* - ** server_write_IV = - ** MD5(ServerHello.random + ClientHello.random); - */ - MD5_Begin(md5Ctx); - MD5_Update(md5Ctx, srcr.data, srcr.len); - MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); - buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item, - "SSL3 Export Server Write IV"); - key_block2 += IVSize; - } - - PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); - } else { - /* - ** Generate TLS Export write keys and IVs. - */ - SECItem secret; - SECItem keyblk; - - secret.type = siBuffer; - keyblk.type = siBuffer; - /* - ** client_write_key[CipherSpec.key_material] - ** final_client_write_key = PRF(client_write_key, - ** "client write key", - ** client_random + server_random); - */ - secret.data = &key_block[i]; - secret.len = effKeySize; - i += effKeySize; - keyblk.data = key_block2; - keyblk.len = keySize; - status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS); - if (status != SECSuccess) { - goto key_and_mac_derive_fail; - } - buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, - "TLS Export Client Write Key"); - key_block2 += keySize; - - /* - ** server_write_key[CipherSpec.key_material] - ** final_server_write_key = PRF(server_write_key, - ** "server write key", - ** client_random + server_random); - */ - secret.data = &key_block[i]; - secret.len = effKeySize; - i += effKeySize; - keyblk.data = key_block2; - keyblk.len = keySize; - status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS); - if (status != SECSuccess) { - goto key_and_mac_derive_fail; - } - buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, - "TLS Export Server Write Key"); - key_block2 += keySize; - - /* - ** iv_block = PRF("", "IV block", client_random + server_random); - ** client_write_IV[SecurityParameters.IV_size] - ** server_write_IV[SecurityParameters.IV_size] - */ - if (IVSize) { - secret.data = NULL; - secret.len = 0; - keyblk.data = key_block2; - keyblk.len = 2 * IVSize; - status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS); - if (status != SECSuccess) { - goto key_and_mac_derive_fail; - } - buildSSLKey(key_block2, IVSize, - &pwSpec->client.write_iv_item, - "TLS Export Client Write IV"); - buildSSLKey(key_block2 + IVSize, IVSize, - &pwSpec->server.write_iv_item, - "TLS Export Server Write IV"); - key_block2 += 2 * IVSize; - } - PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); - } - rv = SECSuccess; - -key_and_mac_derive_fail: - - MD5_DestroyContext(md5Ctx, PR_FALSE); - SHA1_DestroyContext(shaCtx, PR_FALSE); - - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - } - - return rv; -} - -/* derive the Master Secret from the PMS */ -/* Presently, this is only done wtih RSA PMS, and only on the server side, - * so isRSA is always true. - */ -SECStatus -ssl3_MasterSecretDeriveBypass( - ssl3CipherSpec *pwSpec, - const unsigned char *cr, - const unsigned char *sr, - const SECItem *pms, - PRBool isTLS, - PRBool isRSA) -{ - unsigned char *key_block = pwSpec->key_block; - SECStatus rv = SECSuccess; - PRBool isFIPS = PR_FALSE; - PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2; - - SECItem crsr; - - unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; - PRUint64 md5buf[22]; - PRUint64 shabuf[40]; - -#define md5Ctx ((MD5Context *)md5buf) -#define shaCtx ((SHA1Context *)shabuf) - - /* first do the consistancy checks */ - if (isRSA) { - PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH); - if (pms->len != SSL3_RSA_PMS_LENGTH) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* caller must test PMS version for rollback */ - } - - /* initialize the client random, server random block */ - crsr.type = siBuffer; - crsr.data = crsrdata; - crsr.len = sizeof crsrdata; - PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); - PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); - PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len)); - - /* finally do the key gen */ - if (isTLS) { - SECItem master = { siBuffer, NULL, 0 }; - - master.data = key_block; - master.len = SSL3_MASTER_SECRET_LENGTH; - - if (isTLS12) { - rv = TLS_P_hash(HASH_AlgSHA256, pms, "master secret", &crsr, - &master, isFIPS); - } else { - rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS); - } - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - } - } else { - int i; - unsigned int made = 0; - for (i = 0; i < 3; i++) { - unsigned int outLen; - unsigned char sha_out[SHA1_LENGTH]; - - SHA1_Begin(shaCtx); - SHA1_Update(shaCtx, (unsigned char *)mixers[i], i + 1); - SHA1_Update(shaCtx, pms->data, pms->len); - SHA1_Update(shaCtx, crsr.data, crsr.len); - SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); - PORT_Assert(outLen == SHA1_LENGTH); - - MD5_Begin(md5Ctx); - MD5_Update(md5Ctx, pms->data, pms->len); - MD5_Update(md5Ctx, sha_out, outLen); - MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); - PORT_Assert(outLen == MD5_LENGTH); - made += outLen; - } - } - - /* store the results */ - PORT_Memcpy(pwSpec->raw_master_secret, key_block, - SSL3_MASTER_SECRET_LENGTH); - pwSpec->msItem.data = pwSpec->raw_master_secret; - pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH; - PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, - pwSpec->msItem.len)); - - return rv; -} - -static SECStatus -ssl_canExtractMS(PK11SymKey *pms, PRBool isTLS, PRBool isDH, PRBool *pcbp) -{ - SECStatus rv; - PK11SymKey *ms = NULL; - SECItem params = { siBuffer, NULL, 0 }; - CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params; - unsigned char rand[SSL3_RANDOM_LENGTH]; - CK_VERSION pms_version; - CK_MECHANISM_TYPE master_derive; - CK_MECHANISM_TYPE key_derive; - CK_FLAGS keyFlags; - - if (pms == NULL) - return (SECFailure); - - PORT_Memset(rand, 0, SSL3_RANDOM_LENGTH); - - if (isTLS) { - if (isDH) - master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH; - else - master_derive = CKM_TLS_MASTER_KEY_DERIVE; - key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; - keyFlags = CKF_SIGN | CKF_VERIFY; - } else { - if (isDH) - master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH; - else - master_derive = CKM_SSL3_MASTER_KEY_DERIVE; - key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; - keyFlags = 0; - } - - master_params.pVersion = &pms_version; - master_params.RandomInfo.pClientRandom = rand; - master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - master_params.RandomInfo.pServerRandom = rand; - master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH; - - params.data = (unsigned char *)&master_params; - params.len = sizeof master_params; - - ms = PK11_DeriveWithFlags(pms, master_derive, ¶ms, key_derive, - CKA_DERIVE, 0, keyFlags); - if (ms == NULL) - return (SECFailure); - - rv = PK11_ExtractKeyValue(ms); - *pcbp = (rv == SECSuccess); - PK11_FreeSymKey(ms); - - return (rv); -} -#endif /* !NO_PKCS11_BYPASS */ - -/* Check the key exchange algorithm for each cipher in the list to see if - * a master secret key can be extracted. If the KEA will use keys from the - * specified cert make sure the extract operation is attempted from the slot - * where the private key resides. - * If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and - * SECSuccess is returned. In all other cases but one (*pcanbypass) is - * set to FALSE and SECFailure is returned. - * In that last case Derive() has been called successfully but the MS is null, - * CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the - * arguments were all valid but the slot cannot be bypassed. - */ - -/* XXX Add SSL_CBP_TLS1_1 and test it in protocolmask when setting isTLS. */ - -SECStatus -SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey, - PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites, - PRBool *pcanbypass, void *pwArg) -{ -#ifdef NO_PKCS11_BYPASS - if (!pcanbypass) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - *pcanbypass = PR_FALSE; - return SECSuccess; -#else - SECStatus rv; - int i; - PRUint16 suite; - PK11SymKey *pms = NULL; - SECKEYPublicKey *srvPubkey = NULL; - KeyType privKeytype; - PK11SlotInfo *slot = NULL; - SECItem param; - CK_VERSION version; - CK_MECHANISM_TYPE mechanism_array[2]; - SECItem enc_pms = { siBuffer, NULL, 0 }; - PRBool isTLS = PR_FALSE; - SSLCipherSuiteInfo csdef; - PRBool testrsa = PR_FALSE; - PRBool testrsa_export = PR_FALSE; - PRBool testecdh = PR_FALSE; - PRBool testecdhe = PR_FALSE; -#ifndef NSS_DISABLE_ECC - SECKEYECParams ecParams = { siBuffer, NULL, 0 }; -#endif - - if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - srvPubkey = CERT_ExtractPublicKey(cert); - if (!srvPubkey) - return SECFailure; - - *pcanbypass = PR_TRUE; - rv = SECFailure; - - /* determine which KEAs to test */ - /* 0 (TLS_NULL_WITH_NULL_NULL) is used as a list terminator because - * SSL3 and TLS specs forbid negotiating that cipher suite number. - */ - for (i = 0; i < nsuites && (suite = *ciphersuites++) != 0; i++) { - /* skip SSL2 cipher suites and ones NSS doesn't support */ - if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess || - SSL_IS_SSL2_CIPHER(suite)) - continue; - switch (csdef.keaType) { - case ssl_kea_rsa: - switch (csdef.cipherSuite) { - case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA: - case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA: - case TLS_RSA_EXPORT_WITH_RC4_40_MD5: - case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5: - testrsa_export = PR_TRUE; - } - if (!testrsa_export) - testrsa = PR_TRUE; - break; - case ssl_kea_ecdh: - if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */ - testecdhe = PR_TRUE; - else - testecdh = PR_TRUE; - break; - case ssl_kea_dh: - /* this is actually DHE */ - default: - continue; - } - } - - /* For each protocol try to derive and extract an MS. - * Failure of function any function except MS extract means - * continue with the next cipher test. Stop testing when the list is - * exhausted or when the first MS extract--not derive--fails. - */ - privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey); - protocolmask &= SSL_CBP_SSL3 | SSL_CBP_TLS1_0; - while (protocolmask) { - if (protocolmask & SSL_CBP_SSL3) { - isTLS = PR_FALSE; - protocolmask ^= SSL_CBP_SSL3; - } else { - isTLS = PR_TRUE; - protocolmask ^= SSL_CBP_TLS1_0; - } - - if (privKeytype == rsaKey && testrsa_export) { - if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) { - *pcanbypass = PR_FALSE; - rv = SECSuccess; - break; - } else - testrsa = PR_TRUE; - } - for (; privKeytype == rsaKey && testrsa;) { - /* TLS_RSA */ - unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH]; - unsigned int outLen = 0; - CK_MECHANISM_TYPE target; - SECStatus irv; - - mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; - mechanism_array[1] = CKM_RSA_PKCS; - - slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg); - if (slot == NULL) { - PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND); - break; - } - - /* Generate the pre-master secret ... (client side) */ - version.major = 3 /*MSB(clientHelloVersion)*/; - version.minor = 0 /*LSB(clientHelloVersion)*/; - param.data = (unsigned char *)&version; - param.len = sizeof version; - pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, ¶m, 0, pwArg); - PK11_FreeSlot(slot); - if (!pms) - break; - /* now wrap it */ - enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey); - enc_pms.data = (unsigned char *)PORT_Alloc(enc_pms.len); - if (enc_pms.data == NULL) { - PORT_SetError(PR_OUT_OF_MEMORY_ERROR); - break; - } - irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms); - if (irv != SECSuccess) - break; - PK11_FreeSymKey(pms); - pms = NULL; - /* now do the server side--check the triple bypass first */ - rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen, - sizeof rsaPmsBuf, - (unsigned char *)enc_pms.data, - enc_pms.len); - /* if decrypt worked we're done with the RSA test */ - if (rv == SECSuccess) { - *pcanbypass = PR_TRUE; - break; - } - /* check for fallback to double bypass */ - target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE - : CKM_SSL3_MASTER_KEY_DERIVE; - pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms, - target, CKA_DERIVE, 0); - rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass); - if (rv == SECSuccess && *pcanbypass == PR_FALSE) - goto done; - break; - } - - /* Check for NULL to avoid double free. - * SECItem_FreeItem sets data NULL in secitem.c#265 - */ - if (enc_pms.data != NULL) { - SECITEM_FreeItem(&enc_pms, PR_FALSE); - } -#ifndef NSS_DISABLE_ECC - for (; (privKeytype == ecKey && (testecdh || testecdhe)) || - (privKeytype == rsaKey && testecdhe);) { - CK_MECHANISM_TYPE target; - SECKEYPublicKey *keapub = NULL; - SECKEYPrivateKey *keapriv; - SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */ - SECKEYPrivateKey *cpriv = NULL; - SECKEYECParams *pecParams = NULL; - - if (privKeytype == ecKey && testecdhe) { - /* TLS_ECDHE_ECDSA */ - pecParams = &srvPubkey->u.ec.DEREncodedParams; - } else if (privKeytype == rsaKey && testecdhe) { - /* TLS_ECDHE_RSA */ - ECName ec_curve; - int serverKeyStrengthInBits; - int signatureKeyStrength; - int requiredECCbits; - - /* find a curve of equivalent strength to the RSA key's */ - requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey); - if (requiredECCbits < 0) - break; - requiredECCbits *= BPB; - serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len; - if (srvPubkey->u.rsa.modulus.data[0] == 0) { - serverKeyStrengthInBits--; - } - /* convert to strength in bits */ - serverKeyStrengthInBits *= BPB; - - signatureKeyStrength = - SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits); - - if (requiredECCbits > signatureKeyStrength) - requiredECCbits = signatureKeyStrength; - - ec_curve = - ssl3_GetCurveWithECKeyStrength( - ssl3_GetSupportedECCurveMask(NULL), - requiredECCbits); - rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams); - if (rv == SECFailure) { - break; - } - pecParams = &ecParams; - } - - if (testecdhe) { - /* generate server's ephemeral keys */ - keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL); - if (!keapriv || !keapub) { - if (keapriv) - SECKEY_DestroyPrivateKey(keapriv); - if (keapub) - SECKEY_DestroyPublicKey(keapub); - PORT_SetError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - break; - } - } else { - /* TLS_ECDH_ECDSA */ - keapub = srvPubkey; - keapriv = srvPrivkey; - pecParams = &srvPubkey->u.ec.DEREncodedParams; - } - - /* perform client side ops */ - /* generate a pair of ephemeral keys using server's parms */ - cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL); - if (!cpriv || !cpub) { - if (testecdhe) { - SECKEY_DestroyPrivateKey(keapriv); - SECKEY_DestroyPublicKey(keapub); - } - PORT_SetError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - break; - } - /* now do the server side */ - /* determine the PMS using client's public value */ - target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH - : CKM_SSL3_MASTER_KEY_DERIVE_DH; - pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL, - CKM_ECDH1_DERIVE, - target, - CKA_DERIVE, 0, CKD_NULL, NULL, NULL); - rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass); - SECKEY_DestroyPrivateKey(cpriv); - SECKEY_DestroyPublicKey(cpub); - if (testecdhe) { - SECKEY_DestroyPrivateKey(keapriv); - SECKEY_DestroyPublicKey(keapub); - } - if (rv == SECSuccess && *pcanbypass == PR_FALSE) - goto done; - break; - } - /* Check for NULL to avoid double free. */ - if (ecParams.data != NULL) { - PORT_Free(ecParams.data); - ecParams.data = NULL; - } -#endif /* NSS_DISABLE_ECC */ - if (pms) - PK11_FreeSymKey(pms); - } - - /* *pcanbypass has been set */ - rv = SECSuccess; - -done: - if (pms) - PK11_FreeSymKey(pms); - - /* Check for NULL to avoid double free. - * SECItem_FreeItem sets data NULL in secitem.c#265 - */ - if (enc_pms.data != NULL) { - SECITEM_FreeItem(&enc_pms, PR_FALSE); - } -#ifndef NSS_DISABLE_ECC - if (ecParams.data != NULL) { - PORT_Free(ecParams.data); - ecParams.data = NULL; - } -#endif /* NSS_DISABLE_ECC */ - - if (srvPubkey) { - SECKEY_DestroyPublicKey(srvPubkey); - srvPubkey = NULL; - } - - return rv; -#endif /* NO_PKCS11_BYPASS */ -}
diff --git a/net/third_party/nss/ssl/dhe-param.c b/net/third_party/nss/ssl/dhe-param.c deleted file mode 100644 index ac0942e..0000000 --- a/net/third_party/nss/ssl/dhe-param.c +++ /dev/null
@@ -1,413 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -static const unsigned char ff_dhe_g2[] = { 2 }; - -static const unsigned char ff_dhe_2048_p[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, - 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, - 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, - 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, - 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, - 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, - 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, - 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, - 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, - 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, - 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, - 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, - 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, - 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, - 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, - 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, - 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, - 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, - 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, - 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, - 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, - 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, - 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, - 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, - 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, - 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, - 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, - 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, - 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, - 0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -static const ssl3DHParams ff_dhe_2048 = { - { siBuffer, (unsigned char *)ff_dhe_2048_p, sizeof(ff_dhe_2048_p) }, - { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) }, -}; - -static const unsigned char ff_dhe_3072_p[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, - 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, - 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, - 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, - 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, - 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, - 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, - 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, - 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, - 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, - 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, - 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, - 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, - 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, - 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, - 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, - 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, - 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, - 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, - 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, - 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, - 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, - 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, - 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, - 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, - 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, - 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, - 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, - 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, - 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, - 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, - 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, - 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, - 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, - 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, - 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, - 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, - 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, - 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, - 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, - 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, - 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, - 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, - 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, - 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, - 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0xC6, 0x2E, 0x37, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -static const ssl3DHParams ff_dhe_3072 = { - { siBuffer, (unsigned char *)ff_dhe_3072_p, sizeof(ff_dhe_3072_p) }, - { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) }, -}; - -static const unsigned char ff_dhe_4096_p[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, - 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, - 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, - 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, - 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, - 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, - 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, - 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, - 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, - 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, - 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, - 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, - 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, - 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, - 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, - 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, - 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, - 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, - 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, - 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, - 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, - 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, - 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, - 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, - 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, - 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, - 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, - 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, - 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, - 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, - 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, - 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, - 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, - 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, - 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, - 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, - 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, - 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, - 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, - 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, - 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, - 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, - 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, - 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, - 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, - 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, - 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, - 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, - 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, - 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, - 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, - 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, - 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, - 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, - 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, - 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, - 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, - 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, - 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, - 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, - 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, - 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x65, 0x5F, 0x6A, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -static const ssl3DHParams ff_dhe_4096 = { - { siBuffer, (unsigned char *)ff_dhe_4096_p, sizeof(ff_dhe_4096_p) }, - { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) }, -}; - -static const unsigned char ff_dhe_6144_p[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, - 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, - 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, - 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, - 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, - 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, - 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, - 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, - 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, - 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, - 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, - 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, - 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, - 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, - 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, - 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, - 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, - 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, - 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, - 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, - 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, - 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, - 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, - 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, - 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, - 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, - 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, - 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, - 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, - 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, - 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, - 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, - 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, - 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, - 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, - 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, - 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, - 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, - 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, - 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, - 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, - 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, - 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, - 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, - 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, - 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, - 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, - 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, - 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, - 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, - 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, - 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, - 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, - 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, - 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, - 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, - 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, - 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, - 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, - 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, - 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, - 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, - 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, - 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, - 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, - 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, - 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, - 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, - 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, - 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, - 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, - 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, - 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, - 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, - 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, - 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, - 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, - 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, - 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, - 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, - 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, - 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, - 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, - 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, - 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, - 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, - 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, - 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, - 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, - 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, - 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, - 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, - 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, - 0xA4, 0x0E, 0x32, 0x9C, 0xD0, 0xE4, 0x0E, 0x65, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -static const ssl3DHParams ff_dhe_6144 = { - { siBuffer, (unsigned char *)ff_dhe_6144_p, sizeof(ff_dhe_6144_p) }, - { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) }, -}; - -static const unsigned char ff_dhe_8192_p[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, - 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, - 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, - 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, - 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, - 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, - 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, - 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, - 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, - 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, - 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, - 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, - 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, - 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, - 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, - 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, - 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, - 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, - 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, - 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, - 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, - 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, - 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, - 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, - 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, - 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, - 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, - 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, - 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, - 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, - 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, - 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, - 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, - 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, - 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, - 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, - 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, - 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, - 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, - 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, - 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, - 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, - 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, - 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, - 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, - 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, - 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, - 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, - 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, - 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, - 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, - 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, - 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, - 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, - 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, - 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, - 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, - 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, - 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, - 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, - 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, - 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, - 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, - 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, - 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, - 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, - 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, - 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, - 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, - 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, - 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, - 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, - 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, - 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, - 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, - 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, - 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, - 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, - 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, - 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, - 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, - 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, - 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, - 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, - 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, - 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, - 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, - 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, - 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, - 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, - 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, - 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, - 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, - 0xA4, 0x0E, 0x32, 0x9C, 0xCF, 0xF4, 0x6A, 0xAA, - 0x36, 0xAD, 0x00, 0x4C, 0xF6, 0x00, 0xC8, 0x38, - 0x1E, 0x42, 0x5A, 0x31, 0xD9, 0x51, 0xAE, 0x64, - 0xFD, 0xB2, 0x3F, 0xCE, 0xC9, 0x50, 0x9D, 0x43, - 0x68, 0x7F, 0xEB, 0x69, 0xED, 0xD1, 0xCC, 0x5E, - 0x0B, 0x8C, 0xC3, 0xBD, 0xF6, 0x4B, 0x10, 0xEF, - 0x86, 0xB6, 0x31, 0x42, 0xA3, 0xAB, 0x88, 0x29, - 0x55, 0x5B, 0x2F, 0x74, 0x7C, 0x93, 0x26, 0x65, - 0xCB, 0x2C, 0x0F, 0x1C, 0xC0, 0x1B, 0xD7, 0x02, - 0x29, 0x38, 0x88, 0x39, 0xD2, 0xAF, 0x05, 0xE4, - 0x54, 0x50, 0x4A, 0xC7, 0x8B, 0x75, 0x82, 0x82, - 0x28, 0x46, 0xC0, 0xBA, 0x35, 0xC3, 0x5F, 0x5C, - 0x59, 0x16, 0x0C, 0xC0, 0x46, 0xFD, 0x82, 0x51, - 0x54, 0x1F, 0xC6, 0x8C, 0x9C, 0x86, 0xB0, 0x22, - 0xBB, 0x70, 0x99, 0x87, 0x6A, 0x46, 0x0E, 0x74, - 0x51, 0xA8, 0xA9, 0x31, 0x09, 0x70, 0x3F, 0xEE, - 0x1C, 0x21, 0x7E, 0x6C, 0x38, 0x26, 0xE5, 0x2C, - 0x51, 0xAA, 0x69, 0x1E, 0x0E, 0x42, 0x3C, 0xFC, - 0x99, 0xE9, 0xE3, 0x16, 0x50, 0xC1, 0x21, 0x7B, - 0x62, 0x48, 0x16, 0xCD, 0xAD, 0x9A, 0x95, 0xF9, - 0xD5, 0xB8, 0x01, 0x94, 0x88, 0xD9, 0xC0, 0xA0, - 0xA1, 0xFE, 0x30, 0x75, 0xA5, 0x77, 0xE2, 0x31, - 0x83, 0xF8, 0x1D, 0x4A, 0x3F, 0x2F, 0xA4, 0x57, - 0x1E, 0xFC, 0x8C, 0xE0, 0xBA, 0x8A, 0x4F, 0xE8, - 0xB6, 0x85, 0x5D, 0xFE, 0x72, 0xB0, 0xA6, 0x6E, - 0xDE, 0xD2, 0xFB, 0xAB, 0xFB, 0xE5, 0x8A, 0x30, - 0xFA, 0xFA, 0xBE, 0x1C, 0x5D, 0x71, 0xA8, 0x7E, - 0x2F, 0x74, 0x1E, 0xF8, 0xC1, 0xFE, 0x86, 0xFE, - 0xA6, 0xBB, 0xFD, 0xE5, 0x30, 0x67, 0x7F, 0x0D, - 0x97, 0xD1, 0x1D, 0x49, 0xF7, 0xA8, 0x44, 0x3D, - 0x08, 0x22, 0xE5, 0x06, 0xA9, 0xF4, 0x61, 0x4E, - 0x01, 0x1E, 0x2A, 0x94, 0x83, 0x8F, 0xF8, 0x8C, - 0xD6, 0x8C, 0x8B, 0xB7, 0xC5, 0xC6, 0x42, 0x4C, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -static const ssl3DHParams ff_dhe_8192 = { - { siBuffer, (unsigned char *)ff_dhe_8192_p, sizeof(ff_dhe_8192_p) }, - { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) }, -};
diff --git a/net/third_party/nss/ssl/dtlscon.c b/net/third_party/nss/ssl/dtlscon.c deleted file mode 100644 index 35d995e..0000000 --- a/net/third_party/nss/ssl/dtlscon.c +++ /dev/null
@@ -1,1195 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * DTLS Protocol - */ - -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" - -#ifndef PR_ARRAY_SIZE -#define PR_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -static SECStatus dtls_TransmitMessageFlight(sslSocket *ss); -static void dtls_RetransmitTimerExpiredCb(sslSocket *ss); -static SECStatus dtls_SendSavedWriteData(sslSocket *ss); - -/* -28 adjusts for the IP/UDP header */ -static const PRUint16 COMMON_MTU_VALUES[] = { - 1500 - 28, /* Ethernet MTU */ - 1280 - 28, /* IPv6 minimum MTU */ - 576 - 28, /* Common assumption */ - 256 - 28 /* We're in serious trouble now */ -}; - -#define DTLS_COOKIE_BYTES 32 - -/* List copied from ssl3con.c:cipherSuites */ -static const ssl3CipherSuite nonDTLSSuites[] = { -#ifndef NSS_DISABLE_ECC - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS_ECDHE_RSA_WITH_RC4_128_SHA, -#endif /* NSS_DISABLE_ECC */ - TLS_DHE_DSS_WITH_RC4_128_SHA, -#ifndef NSS_DISABLE_ECC - TLS_ECDH_RSA_WITH_RC4_128_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, -#endif /* NSS_DISABLE_ECC */ - TLS_RSA_WITH_RC4_128_MD5, - TLS_RSA_WITH_RC4_128_SHA, - TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - TLS_RSA_EXPORT_WITH_RC4_40_MD5, - 0 /* End of list marker */ -}; - -/* Map back and forth between TLS and DTLS versions in wire format. - * Mapping table is: - * - * TLS DTLS - * 1.1 (0302) 1.0 (feff) - * 1.2 (0303) 1.2 (fefd) - * 1.3 (0304) 1.3 (fefc) - */ -SSL3ProtocolVersion -dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv) -{ - if (tlsv == SSL_LIBRARY_VERSION_TLS_1_1) { - return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE; - } - if (tlsv == SSL_LIBRARY_VERSION_TLS_1_2) { - return SSL_LIBRARY_VERSION_DTLS_1_2_WIRE; - } - if (tlsv == SSL_LIBRARY_VERSION_TLS_1_3) { - return SSL_LIBRARY_VERSION_DTLS_1_3_WIRE; - } - - /* Anything other than TLS 1.1 or 1.2 is an error, so return - * the invalid version 0xffff. */ - return 0xffff; -} - -/* Map known DTLS versions to known TLS versions. - * - Invalid versions (< 1.0) return a version of 0 - * - Versions > known return a version one higher than we know of - * to accomodate a theoretically newer version */ -SSL3ProtocolVersion -dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv) -{ - if (MSB(dtlsv) == 0xff) { - return 0; - } - - if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) { - return SSL_LIBRARY_VERSION_TLS_1_1; - } - /* Handle the skipped version of DTLS 1.1 by returning - * an error. */ - if (dtlsv == ((~0x0101) & 0xffff)) { - return 0; - } - if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_2_WIRE) { - return SSL_LIBRARY_VERSION_TLS_1_2; - } - if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_3_WIRE) { - return SSL_LIBRARY_VERSION_TLS_1_3; - } - - /* Return a fictional higher version than we know of */ - return SSL_LIBRARY_VERSION_MAX_SUPPORTED + 1; -} - -/* On this socket, Disable non-DTLS cipher suites in the argument's list */ -SECStatus -ssl3_DisableNonDTLSSuites(sslSocket *ss) -{ - const ssl3CipherSuite *suite; - - for (suite = nonDTLSSuites; *suite; ++suite) { - PORT_CheckSuccess(ssl3_CipherPrefSet(ss, *suite, PR_FALSE)); - } - return SECSuccess; -} - -/* Allocate a DTLSQueuedMessage. - * - * Called from dtls_QueueMessage() - */ -static DTLSQueuedMessage * -dtls_AllocQueuedMessage(PRUint16 epoch, SSL3ContentType type, - const unsigned char *data, PRUint32 len) -{ - DTLSQueuedMessage *msg = NULL; - - msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage)); - if (!msg) - return NULL; - - msg->data = PORT_Alloc(len); - if (!msg->data) { - PORT_Free(msg); - return NULL; - } - PORT_Memcpy(msg->data, data, len); - - msg->len = len; - msg->epoch = epoch; - msg->type = type; - - return msg; -} - -/* - * Free a handshake message - * - * Called from dtls_FreeHandshakeMessages() - */ -static void -dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg) -{ - if (!msg) - return; - - PORT_ZFree(msg->data, msg->len); - PORT_Free(msg); -} - -/* - * Free a list of handshake messages - * - * Called from: - * dtls_HandleHandshake() - * ssl3_DestroySSL3Info() - */ -void -dtls_FreeHandshakeMessages(PRCList *list) -{ - PRCList *cur_p; - - while (!PR_CLIST_IS_EMPTY(list)) { - cur_p = PR_LIST_TAIL(list); - PR_REMOVE_LINK(cur_p); - dtls_FreeHandshakeMessage((DTLSQueuedMessage *)cur_p); - } -} - -/* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record. - * origBuf is the decrypted ssl record content and is expected to contain - * complete handshake records - * Caller must hold the handshake and RecvBuf locks. - * - * Note that this code uses msg_len for two purposes: - * - * (1) To pass the length to ssl3_HandleHandshakeMessage() - * (2) To carry the length of a message currently being reassembled - * - * However, unlike ssl3_HandleHandshake(), it is not used to carry - * the state of reassembly (i.e., whether one is in progress). That - * is carried in recvdHighWater and recvdFragments. - */ -#define OFFSET_BYTE(o) (o / 8) -#define OFFSET_MASK(o) (1 << (o % 8)) - -SECStatus -dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) -{ - /* XXX OK for now. - * This doesn't work properly with asynchronous certificate validation. - * because that returns a WOULDBLOCK error. The current DTLS - * applications do not need asynchronous validation, but in the - * future we will need to add this. - */ - sslBuffer buf = *origBuf; - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - while (buf.len > 0) { - PRUint8 type; - PRUint32 message_length; - PRUint16 message_seq; - PRUint32 fragment_offset; - PRUint32 fragment_length; - PRUint32 offset; - - if (buf.len < 12) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); - rv = SECFailure; - break; - } - - /* Parse the header */ - type = buf.buf[0]; - message_length = (buf.buf[1] << 16) | (buf.buf[2] << 8) | buf.buf[3]; - message_seq = (buf.buf[4] << 8) | buf.buf[5]; - fragment_offset = (buf.buf[6] << 16) | (buf.buf[7] << 8) | buf.buf[8]; - fragment_length = (buf.buf[9] << 16) | (buf.buf[10] << 8) | buf.buf[11]; - -#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */ - if (message_length > MAX_HANDSHAKE_MSG_LEN) { - (void)ssl3_DecodeError(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); - return SECFailure; - } -#undef MAX_HANDSHAKE_MSG_LEN - - buf.buf += 12; - buf.len -= 12; - - /* This fragment must be complete */ - if (buf.len < fragment_length) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); - rv = SECFailure; - break; - } - - /* Sanity check the packet contents */ - if ((fragment_length + fragment_offset) > message_length) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); - rv = SECFailure; - break; - } - - /* There are three ways we could not be ready for this packet. - * - * 1. It's a partial next message. - * 2. It's a partial or complete message beyond the next - * 3. It's a message we've already seen - * - * If it's the complete next message we accept it right away. - * This is the common case for short messages - */ - if ((message_seq == ss->ssl3.hs.recvMessageSeq) && - (fragment_offset == 0) && - (fragment_length == message_length)) { - /* Complete next message. Process immediately */ - ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; - ss->ssl3.hs.msg_len = message_length; - - /* At this point we are advancing our state machine, so - * we can free our last flight of messages */ - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); - ss->ssl3.hs.recvdHighWater = -1; - dtls_CancelTimer(ss); - - /* Reset the timer to the initial value if the retry counter - * is 0, per Sec. 4.2.4.1 */ - if (ss->ssl3.hs.rtRetries == 0) { - ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; - } - - rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len); - if (rv == SECFailure) { - /* Do not attempt to process rest of messages in this record */ - break; - } - } else { - if (message_seq < ss->ssl3.hs.recvMessageSeq) { - /* Case 3: we do an immediate retransmit if we're - * in a waiting state*/ - if (ss->ssl3.hs.rtTimerCb == NULL) { - /* Ignore */ - } else if (ss->ssl3.hs.rtTimerCb == - dtls_RetransmitTimerExpiredCb) { - SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected", - SSL_GETPID(), ss->fd)); - /* Check to see if we retransmitted recently. If so, - * suppress the triggered retransmit. This avoids - * retransmit wars after packet loss. - * This is not in RFC 5346 but should be - */ - if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > - (ss->ssl3.hs.rtTimeoutMs / 4)) { - SSL_TRC(30, - ("%d: SSL3[%d]: Shortcutting retransmit timer", - SSL_GETPID(), ss->fd)); - - /* Cancel the timer and call the CB, - * which re-arms the timer */ - dtls_CancelTimer(ss); - dtls_RetransmitTimerExpiredCb(ss); - rv = SECSuccess; - break; - } else { - SSL_TRC(30, - ("%d: SSL3[%d]: We just retransmitted. Ignoring.", - SSL_GETPID(), ss->fd)); - rv = SECSuccess; - break; - } - } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) { - /* Retransmit the messages and re-arm the timer - * Note that we are not backing off the timer here. - * The spec isn't clear and my reasoning is that this - * may be a re-ordered packet rather than slowness, - * so let's be aggressive. */ - dtls_CancelTimer(ss); - rv = dtls_TransmitMessageFlight(ss); - if (rv == SECSuccess) { - rv = dtls_StartTimer(ss, dtls_FinishedTimerCb); - } - if (rv != SECSuccess) - return rv; - break; - } - } else if (message_seq > ss->ssl3.hs.recvMessageSeq) { - /* Case 2 - * - * Ignore this message. This means we don't handle out of - * order complete messages that well, but we're still - * compliant and this probably does not happen often - * - * XXX OK for now. Maybe do something smarter at some point? - */ - } else { - /* Case 1 - * - * Buffer the fragment for reassembly - */ - /* Make room for the message */ - if (ss->ssl3.hs.recvdHighWater == -1) { - PRUint32 map_length = OFFSET_BYTE(message_length) + 1; - - rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length); - if (rv != SECSuccess) - break; - /* Make room for the fragment map */ - rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments, - map_length); - if (rv != SECSuccess) - break; - - /* Reset the reassembly map */ - ss->ssl3.hs.recvdHighWater = 0; - PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0, - ss->ssl3.hs.recvdFragments.space); - ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; - ss->ssl3.hs.msg_len = message_length; - } - - /* If we have a message length mismatch, abandon the reassembly - * in progress and hope that the next retransmit will give us - * something sane - */ - if (message_length != ss->ssl3.hs.msg_len) { - ss->ssl3.hs.recvdHighWater = -1; - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); - rv = SECFailure; - break; - } - - /* Now copy this fragment into the buffer */ - PORT_Assert((fragment_offset + fragment_length) <= - ss->ssl3.hs.msg_body.space); - PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset, - buf.buf, fragment_length); - - /* This logic is a bit tricky. We have two values for - * reassembly state: - * - * - recvdHighWater contains the highest contiguous number of - * bytes received - * - recvdFragments contains a bitmask of packets received - * above recvdHighWater - * - * This avoids having to fill in the bitmask in the common - * case of adjacent fragments received in sequence - */ - if (fragment_offset <= (unsigned int)ss->ssl3.hs.recvdHighWater) { - /* Either this is the adjacent fragment or an overlapping - * fragment */ - ss->ssl3.hs.recvdHighWater = fragment_offset + - fragment_length; - } else { - for (offset = fragment_offset; - offset < fragment_offset + fragment_length; - offset++) { - ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |= - OFFSET_MASK(offset); - } - } - - /* Now figure out the new high water mark if appropriate */ - for (offset = ss->ssl3.hs.recvdHighWater; - offset < ss->ssl3.hs.msg_len; offset++) { - /* Note that this loop is not efficient, since it counts - * bit by bit. If we have a lot of out-of-order packets, - * we should optimize this */ - if (ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] & - OFFSET_MASK(offset)) { - ss->ssl3.hs.recvdHighWater++; - } else { - break; - } - } - - /* If we have all the bytes, then we are good to go */ - if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) { - ss->ssl3.hs.recvdHighWater = -1; - - rv = ssl3_HandleHandshakeMessage(ss, - ss->ssl3.hs.msg_body.buf, - ss->ssl3.hs.msg_len); - if (rv == SECFailure) - break; /* Skip rest of record */ - - /* At this point we are advancing our state machine, so - * we can free our last flight of messages */ - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); - dtls_CancelTimer(ss); - - /* If there have been no retries this time, reset the - * timer value to the default per Section 4.2.4.1 */ - if (ss->ssl3.hs.rtRetries == 0) { - ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; - } - } - } - } - - buf.buf += fragment_length; - buf.len -= fragment_length; - } - - origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */ - - /* XXX OK for now. In future handle rv == SECWouldBlock safely in order - * to deal with asynchronous certificate verification */ - return rv; -} - -/* Enqueue a message (either handshake or CCS) - * - * Called from: - * dtls_StageHandshakeMessage() - * ssl3_SendChangeCipherSpecs() - */ -SECStatus -dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, - const SSL3Opaque *pIn, PRInt32 nIn) -{ - SECStatus rv = SECSuccess; - DTLSQueuedMessage *msg = NULL; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - msg = dtls_AllocQueuedMessage(ss->ssl3.cwSpec->epoch, type, pIn, nIn); - - if (!msg) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - rv = SECFailure; - } else { - PR_APPEND_LINK(&msg->link, &ss->ssl3.hs.lastMessageFlight); - } - - return rv; -} - -/* Add DTLS handshake message to the pending queue - * Empty the sendBuf buffer. - * This function returns SECSuccess or SECFailure, never SECWouldBlock. - * Always set sendBuf.len to 0, even when returning SECFailure. - * - * Called from: - * ssl3_AppendHandshakeHeader() - * dtls_FlushHandshake() - */ -SECStatus -dtls_StageHandshakeMessage(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - /* This function is sometimes called when no data is actually to - * be staged, so just return SECSuccess. */ - if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) - return rv; - - rv = dtls_QueueMessage(ss, content_handshake, - ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len); - - /* Whether we succeeded or failed, toss the old handshake data. */ - ss->sec.ci.sendBuf.len = 0; - return rv; -} - -/* Enqueue the handshake message in sendBuf (if any) and then - * transmit the resulting flight of handshake messages. - * - * Called from: - * ssl3_FlushHandshake() - */ -SECStatus -dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) -{ - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - rv = dtls_StageHandshakeMessage(ss); - if (rv != SECSuccess) - return rv; - - if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - rv = dtls_TransmitMessageFlight(ss); - if (rv != SECSuccess) - return rv; - - if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) { - ss->ssl3.hs.rtRetries = 0; - rv = dtls_StartTimer(ss, dtls_RetransmitTimerExpiredCb); - } - } - - return rv; -} - -/* The callback for when the retransmit timer expires - * - * Called from: - * dtls_CheckTimer() - * dtls_HandleHandshake() - */ -static void -dtls_RetransmitTimerExpiredCb(sslSocket *ss) -{ - SECStatus rv = SECFailure; - - ss->ssl3.hs.rtRetries++; - - if (!(ss->ssl3.hs.rtRetries % 3)) { - /* If one of the messages was potentially greater than > MTU, - * then downgrade. Do this every time we have retransmitted a - * message twice, per RFC 6347 Sec. 4.1.1 */ - dtls_SetMTU(ss, ss->ssl3.hs.maxMessageSent - 1); - } - - rv = dtls_TransmitMessageFlight(ss); - if (rv == SECSuccess) { - - /* Re-arm the timer */ - rv = dtls_RestartTimer(ss, PR_TRUE, dtls_RetransmitTimerExpiredCb); - } - - if (rv == SECFailure) { - /* XXX OK for now. In future maybe signal the stack that we couldn't - * transmit. For now, let the read handle any real network errors */ - } -} - -/* Transmit a flight of handshake messages, stuffing them - * into as few records as seems reasonable - * - * Called from: - * dtls_FlushHandshake() - * dtls_RetransmitTimerExpiredCb() - */ -static SECStatus -dtls_TransmitMessageFlight(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - PRCList *msg_p; - PRUint16 room_left = ss->ssl3.mtu; - PRInt32 sent; - - ssl_GetXmitBufLock(ss); - ssl_GetSpecReadLock(ss); - - /* DTLS does not buffer its handshake messages in - * ss->pendingBuf, but rather in the lastMessageFlight - * structure. This is just a sanity check that - * some programming error hasn't inadvertantly - * stuffed something in ss->pendingBuf - */ - PORT_Assert(!ss->pendingBuf.len); - for (msg_p = PR_LIST_HEAD(&ss->ssl3.hs.lastMessageFlight); - msg_p != &ss->ssl3.hs.lastMessageFlight; - msg_p = PR_NEXT_LINK(msg_p)) { - DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p; - - /* The logic here is: - * - * 1. If this is a message that will not fit into the remaining - * space, then flush. - * 2. If the message will now fit into the remaining space, - * encrypt, buffer, and loop. - * 3. If the message will not fit, then fragment. - * - * At the end of the function, flush. - */ - if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) { - /* The message will not fit into the remaining space, so flush */ - rv = dtls_SendSavedWriteData(ss); - if (rv != SECSuccess) - break; - - room_left = ss->ssl3.mtu; - } - - if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) { - /* The message will fit, so encrypt and then continue with the - * next packet */ - sent = ssl3_SendRecord(ss, msg->epoch, msg->type, - msg->data, msg->len, - ssl_SEND_FLAG_FORCE_INTO_BUFFER | - ssl_SEND_FLAG_USE_EPOCH); - if (sent != msg->len) { - rv = SECFailure; - if (sent != -1) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } - break; - } - - room_left = ss->ssl3.mtu - ss->pendingBuf.len; - } else { - /* The message will not fit, so fragment. - * - * XXX OK for now. Arrange to coalesce the last fragment - * of this message with the next message if possible. - * That would be more efficient. - */ - PRUint32 fragment_offset = 0; - unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest - * plausible MTU */ - - /* Assert that we have already flushed */ - PORT_Assert(room_left == ss->ssl3.mtu); - - /* Case 3: We now need to fragment this message - * DTLS only supports fragmenting handshaking messages */ - PORT_Assert(msg->type == content_handshake); - - /* The headers consume 12 bytes so the smalles possible - * message (i.e., an empty one) is 12 bytes - */ - PORT_Assert(msg->len >= 12); - - while ((fragment_offset + 12) < msg->len) { - PRUint32 fragment_len; - const unsigned char *content = msg->data + 12; - PRUint32 content_len = msg->len - 12; - - /* The reason we use 8 here is that that's the length of - * the new DTLS data that we add to the header */ - fragment_len = PR_MIN((PRUint32)room_left - (SSL3_BUFFER_FUDGE + 8), - content_len - fragment_offset); - PORT_Assert(fragment_len < DTLS_MAX_MTU - 12); - /* Make totally sure that we are within the buffer. - * Note that the only way that fragment len could get - * adjusted here is if - * - * (a) we are in release mode so the PORT_Assert is compiled out - * (b) either the MTU table is inconsistent with DTLS_MAX_MTU - * or ss->ssl3.mtu has become corrupt. - */ - fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12); - - /* Construct an appropriate-sized fragment */ - /* Type, length, sequence */ - PORT_Memcpy(fragment, msg->data, 6); - - /* Offset */ - fragment[6] = (fragment_offset >> 16) & 0xff; - fragment[7] = (fragment_offset >> 8) & 0xff; - fragment[8] = (fragment_offset)&0xff; - - /* Fragment length */ - fragment[9] = (fragment_len >> 16) & 0xff; - fragment[10] = (fragment_len >> 8) & 0xff; - fragment[11] = (fragment_len)&0xff; - - PORT_Memcpy(fragment + 12, content + fragment_offset, - fragment_len); - - /* - * Send the record. We do this in two stages - * 1. Encrypt - */ - sent = ssl3_SendRecord(ss, msg->epoch, msg->type, - fragment, fragment_len + 12, - ssl_SEND_FLAG_FORCE_INTO_BUFFER | - ssl_SEND_FLAG_USE_EPOCH); - if (sent != (fragment_len + 12)) { - rv = SECFailure; - if (sent != -1) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } - break; - } - - /* 2. Flush */ - rv = dtls_SendSavedWriteData(ss); - if (rv != SECSuccess) - break; - - fragment_offset += fragment_len; - } - } - } - - /* Finally, we need to flush */ - if (rv == SECSuccess) - rv = dtls_SendSavedWriteData(ss); - - /* Give up the locks */ - ssl_ReleaseSpecReadLock(ss); - ssl_ReleaseXmitBufLock(ss); - - return rv; -} - -/* Flush the data in the pendingBuf and update the max message sent - * so we can adjust the MTU estimate if we need to. - * Wrapper for ssl_SendSavedWriteData. - * - * Called from dtls_TransmitMessageFlight() - */ -static SECStatus -dtls_SendSavedWriteData(sslSocket *ss) -{ - PRInt32 sent; - - sent = ssl_SendSavedWriteData(ss); - if (sent < 0) - return SECFailure; - - /* We should always have complete writes b/c datagram sockets - * don't really block */ - if (ss->pendingBuf.len > 0) { - ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return SECFailure; - } - - /* Update the largest message sent so we can adjust the MTU - * estimate if necessary */ - if (sent > ss->ssl3.hs.maxMessageSent) - ss->ssl3.hs.maxMessageSent = sent; - - return SECSuccess; -} - -/* Compress, MAC, encrypt a DTLS record. Allows specification of - * the epoch using epoch value. If use_epoch is PR_TRUE then - * we use the provided epoch. If use_epoch is PR_FALSE then - * whatever the current value is in effect is used. - * - * Called from ssl3_SendRecord() - */ -SECStatus -dtls_CompressMACEncryptRecord(sslSocket *ss, - DTLSEpoch epoch, - PRBool use_epoch, - SSL3ContentType type, - const SSL3Opaque *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf) -{ - SECStatus rv = SECFailure; - ssl3CipherSpec *cwSpec; - - ssl_GetSpecReadLock(ss); /********************************/ - - /* The reason for this switch-hitting code is that we might have - * a flight of records spanning an epoch boundary, e.g., - * - * ClientKeyExchange (epoch = 0) - * ChangeCipherSpec (epoch = 0) - * Finished (epoch = 1) - * - * Thus, each record needs a different cipher spec. The information - * about which epoch to use is carried with the record. - */ - if (use_epoch) { - if (ss->ssl3.cwSpec->epoch == epoch) - cwSpec = ss->ssl3.cwSpec; - else if (ss->ssl3.pwSpec->epoch == epoch) - cwSpec = ss->ssl3.pwSpec; - else - cwSpec = NULL; - } else { - cwSpec = ss->ssl3.cwSpec; - } - - if (cwSpec) { - if (ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE, - PR_FALSE, type, pIn, contentLen, - wrBuf); - } else { - rv = tls13_ProtectRecord(ss, type, pIn, contentLen, wrBuf); - } - } else { - PR_NOT_REACHED("Couldn't find a cipher spec matching epoch"); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } - ssl_ReleaseSpecReadLock(ss); /************************************/ - - return rv; -} - -/* Start a timer - * - * Called from: - * dtls_HandleHandshake() - * dtls_FlushHAndshake() - * dtls_RestartTimer() - */ -SECStatus -dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb) -{ - PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); - - ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); - ss->ssl3.hs.rtTimerCb = cb; - - return SECSuccess; -} - -/* Restart a timer with optional backoff - * - * Called from dtls_RetransmitTimerExpiredCb() - */ -SECStatus -dtls_RestartTimer(sslSocket *ss, PRBool backoff, DTLSTimerCb cb) -{ - if (backoff) { - ss->ssl3.hs.rtTimeoutMs *= 2; - if (ss->ssl3.hs.rtTimeoutMs > MAX_DTLS_TIMEOUT_MS) - ss->ssl3.hs.rtTimeoutMs = MAX_DTLS_TIMEOUT_MS; - } - - return dtls_StartTimer(ss, cb); -} - -/* Cancel a pending timer - * - * Called from: - * dtls_HandleHandshake() - * dtls_CheckTimer() - */ -void -dtls_CancelTimer(sslSocket *ss) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - ss->ssl3.hs.rtTimerCb = NULL; -} - -/* Check the pending timer and fire the callback if it expired - * - * Called from ssl3_GatherCompleteHandshake() - */ -void -dtls_CheckTimer(sslSocket *ss) -{ - if (!ss->ssl3.hs.rtTimerCb) - return; - - if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > - PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) { - /* Timer has expired */ - DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb; - - /* Cancel the timer so that we can call the CB safely */ - dtls_CancelTimer(ss); - - /* Now call the CB */ - cb(ss); - } -} - -/* The callback to fire when the holddown timer for the Finished - * message expires and we can delete it - * - * Called from dtls_CheckTimer() - */ -void -dtls_FinishedTimerCb(sslSocket *ss) -{ - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); -} - -/* Cancel the Finished hold-down timer and destroy the - * pending cipher spec. Note that this means that - * successive rehandshakes will fail if the Finished is - * lost. - * - * XXX OK for now. Figure out how to handle the combination - * of Finished lost and rehandshake - */ -void -dtls_RehandshakeCleanup(sslSocket *ss) -{ - dtls_CancelTimer(ss); - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); - ss->ssl3.hs.sendMessageSeq = 0; - ss->ssl3.hs.recvMessageSeq = 0; -} - -/* Set the MTU to the next step less than or equal to the - * advertised value. Also used to downgrade the MTU by - * doing dtls_SetMTU(ss, biggest packet set). - * - * Passing 0 means set this to the largest MTU known - * (effectively resetting the PMTU backoff value). - * - * Called by: - * ssl3_InitState() - * dtls_RetransmitTimerExpiredCb() - */ -void -dtls_SetMTU(sslSocket *ss, PRUint16 advertised) -{ - int i; - - if (advertised == 0) { - ss->ssl3.mtu = COMMON_MTU_VALUES[0]; - SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); - return; - } - - for (i = 0; i < PR_ARRAY_SIZE(COMMON_MTU_VALUES); i++) { - if (COMMON_MTU_VALUES[i] <= advertised) { - ss->ssl3.mtu = COMMON_MTU_VALUES[i]; - SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); - return; - } - } - - /* Fallback */ - ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES) - 1]; - SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); -} - -/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a - * DTLS hello_verify_request - * Caller must hold Handshake and RecvBuf locks. - */ -SECStatus -dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST; - SECStatus rv; - PRInt32 temp; - SECItem cookie = { siBuffer, NULL, 0 }; - SSL3AlertDescription desc = illegal_parameter; - - SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.hs.ws != wait_server_hello) { - errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST; - desc = unexpected_message; - goto alert_loser; - } - - /* The version */ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (temp < 0) { - goto loser; /* alert has been sent */ - } - - if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE && - temp != SSL_LIBRARY_VERSION_DTLS_1_2_WIRE) { - goto alert_loser; - } - - /* The cookie */ - rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* alert has been sent */ - } - if (cookie.len > DTLS_COOKIE_BYTES) { - desc = decode_error; - goto alert_loser; /* malformed. */ - } - - PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len); - ss->ssl3.hs.cookieLen = cookie.len; - - ssl_GetXmitBufLock(ss); /*******************************/ - - /* Now re-send the client hello */ - rv = ssl3_SendClientHello(ss, PR_TRUE); - - ssl_ReleaseXmitBufLock(ss); /*******************************/ - - if (rv == SECSuccess) - return rv; - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, desc); - -loser: - ssl_MapLowLevelError(errCode); - return SECFailure; -} - -/* Initialize the DTLS anti-replay window - * - * Called from: - * ssl3_SetupPendingCipherSpec() - * ssl3_InitCipherSpec() - */ -void -dtls_InitRecvdRecords(DTLSRecvdRecords *records) -{ - PORT_Memset(records->data, 0, sizeof(records->data)); - records->left = 0; - records->right = DTLS_RECVD_RECORDS_WINDOW - 1; -} - -/* - * Has this DTLS record been received? Return values are: - * -1 -- out of range to the left - * 0 -- not received yet - * 1 -- replay - * - * Called from: ssl3_HandleRecord() - */ -int -dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq) -{ - PRUint64 offset; - - /* Out of range to the left */ - if (seq < records->left) { - return -1; - } - - /* Out of range to the right; since we advance the window on - * receipt, that means that this packet has not been received - * yet */ - if (seq > records->right) - return 0; - - offset = seq % DTLS_RECVD_RECORDS_WINDOW; - - return !!(records->data[offset / 8] & (1 << (offset % 8))); -} - -/* Update the DTLS anti-replay window - * - * Called from ssl3_HandleRecord() - */ -void -dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq) -{ - PRUint64 offset; - - if (seq < records->left) - return; - - if (seq > records->right) { - PRUint64 new_left; - PRUint64 new_right; - PRUint64 right; - - /* Slide to the right; this is the tricky part - * - * 1. new_top is set to have room for seq, on the - * next byte boundary by setting the right 8 - * bits of seq - * 2. new_left is set to compensate. - * 3. Zero all bits between top and new_top. Since - * this is a ring, this zeroes everything as-yet - * unseen. Because we always operate on byte - * boundaries, we can zero one byte at a time - */ - new_right = seq | 0x07; - new_left = (new_right - DTLS_RECVD_RECORDS_WINDOW) + 1; - - for (right = records->right + 8; right <= new_right; right += 8) { - offset = right % DTLS_RECVD_RECORDS_WINDOW; - records->data[offset / 8] = 0; - } - - records->right = new_right; - records->left = new_left; - } - - offset = seq % DTLS_RECVD_RECORDS_WINDOW; - - records->data[offset / 8] |= (1 << (offset % 8)); -} - -SECStatus -DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout) -{ - sslSocket *ss = NULL; - PRIntervalTime elapsed; - PRIntervalTime desired; - - ss = ssl_FindSocket(socket); - - if (!ss) - return SECFailure; - - if (!IS_DTLS(ss)) - return SECFailure; - - if (!ss->ssl3.hs.rtTimerCb) - return SECFailure; - - elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted; - desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs); - if (elapsed > desired) { - /* Timer expired */ - *timeout = PR_INTERVAL_NO_WAIT; - } else { - *timeout = desired - elapsed; - } - - return SECSuccess; -} - -/* - * DTLS relevance checks: - * Note that this code currently ignores all out-of-epoch packets, - * which means we lose some in the case of rehandshake + - * loss/reordering. Since DTLS is explicitly unreliable, this - * seems like a good tradeoff for implementation effort and is - * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1. - * - * If the packet is not relevant, this function returns PR_FALSE. - * If the packet is relevant, this function returns PR_TRUE - * and sets |*seqNum| to the packet sequence number. - */ -PRBool -dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec, - const SSL3Ciphertext *cText, PRUint64 *seqNum) -{ - DTLSEpoch epoch = cText->seq_num.high >> 16; - PRUint64 dtls_seq_num; - - if (crSpec->epoch != epoch) { - SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, received packet " - "from irrelevant epoch %d", - SSL_GETPID(), ss->fd, epoch)); - return PR_FALSE; - } - - dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) | - ((PRUint64)cText->seq_num.low); - - if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) { - SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, rejecting " - "potentially replayed packet", - SSL_GETPID(), ss->fd)); - return PR_FALSE; - } - - *seqNum = dtls_seq_num; - return PR_TRUE; -}
diff --git a/net/third_party/nss/ssl/manifest.mn b/net/third_party/nss/ssl/manifest.mn deleted file mode 100644 index 1366d15e..0000000 --- a/net/third_party/nss/ssl/manifest.mn +++ /dev/null
@@ -1,55 +0,0 @@ -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -CORE_DEPTH = ../.. - -# DEFINES = -DTRACE - -EXPORTS = \ - ssl.h \ - sslt.h \ - sslerr.h \ - sslproto.h \ - preenc.h \ - $(NULL) - -MODULE = nss -MAPFILE = $(OBJDIR)/ssl.def - -CSRCS = \ - derive.c \ - dtlscon.c \ - prelib.c \ - ssl3con.c \ - ssl3gthr.c \ - sslauth.c \ - sslcon.c \ - ssldef.c \ - sslenum.c \ - sslerr.c \ - sslerrstrs.c \ - sslinit.c \ - ssl3ext.c \ - sslgathr.c \ - sslmutex.c \ - sslnonce.c \ - sslreveal.c \ - sslsecur.c \ - sslsnce.c \ - sslsock.c \ - ssltrace.c \ - sslver.c \ - authcert.c \ - cmpcert.c \ - sslinfo.c \ - ssl3ecc.c \ - tls13con.c \ - tls13hkdf.c \ - $(NULL) - -LIBRARY_NAME = ssl -LIBRARY_VERSION = 3 - -# This part of the code, including all sub-dirs, can be optimized for size -export ALLOW_OPT_CODE_SIZE = 1
diff --git a/net/third_party/nss/ssl/notes.txt b/net/third_party/nss/ssl/notes.txt deleted file mode 100644 index cf514ad2..0000000 --- a/net/third_party/nss/ssl/notes.txt +++ /dev/null
@@ -1,134 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -SSL's Buffers: enumerated and explained. - ---------------------------------------------------------------------------- -incoming: - -gs = ss->gather -hs = ss->ssl3->hs - -gs->inbuf SSL3 only: incoming (encrypted) ssl records are placed here, - and then decrypted (or copied) to gs->buf. - -gs->buf SSL2: incoming SSL records are put here, and then decrypted - in place. - SSL3: ssl3_HandleHandshake puts decrypted ssl records here. - -hs.msg_body (SSL3 only) When an incoming handshake message spans more - than one ssl record, the first part(s) of it are accumulated - here until it all arrives. - -hs.msgState (SSL3 only) an alternative set of pointers/lengths for gs->buf. - Used only when a handleHandshake function returns SECWouldBlock. - ssl3_HandleHandshake remembers how far it previously got by - using these pointers instead of gs->buf when it is called - after a previous SECWouldBlock return. - ---------------------------------------------------------------------------- -outgoing: - -sec = ss->sec -ci = ss->sec->ci /* connect info */ - -ci->sendBuf Outgoing handshake messages are appended to this buffer. - This buffer will then be sent as a single SSL record. - -sec->writeBuf outgoing ssl records are constructed here and encrypted in - place before being written or copied to pendingBuf. - -ss->pendingBuf contains outgoing ciphertext that was saved after a write - attempt to the socket failed, e.g. EWouldBlock. - Generally empty with blocking sockets (should be no incomplete - writes). - -ss->saveBuf Used only by socks code. Intended to be used to buffer - outgoing data until a socks handshake completes. However, - this buffer is always empty. There is no code to put - anything into it. - ---------------------------------------------------------------------------- - -SECWouldBlock means that the function cannot make progress because it is -waiting for some event OTHER THAN socket I/O completion (e.g. waiting for -user dialog to finish). It is not the same as EWOULDBLOCK. - ---------------------------------------------------------------------------- - -Rank (order) of locks - -recvLock ->\ firstHandshake -> recvbuf -> ssl3Handshake -> xmitbuf -> "spec" -sendLock ->/ - -crypto and hash Data that must be protected while turning plaintext into -ciphertext: - -SSL2: (in ssl2_Send*) - sec->hash* - sec->hashcx (ptr and data) - sec->enc - sec->writecx* (ptr and content) - sec->sendSecret*(ptr and content) - sec->sendSequence locked by xmitBufLock - sec->blockSize - sec->writeBuf* (ptr & content) locked by xmitBufLock - "in" locked by xmitBufLock - -SSl3: (in ssl3_SendPlainText) - ss->ssl3 (the pointer) - ss->ssl3->current_write* (the pointer and the data in the spec - and any data referenced by the spec. - - ss->sec->isServer - ss->sec->writebuf* (ptr & content) locked by xmitBufLock - "buf" locked by xmitBufLock - -crypto and hash data that must be protected while turning ciphertext into -plaintext: - -SSL2: (in ssl2_GatherData) - gs->* (locked by recvBufLock ) - sec->dec - sec->readcx - sec->hash* (ptr and data) - sec->hashcx (ptr and data) - -SSL3: (in ssl3_HandleRecord ) - ssl3->current_read* (the pointer and all data refernced) - ss->sec->isServer - - -Data that must be protected while being used by a "writer": - -ss->pendingBuf.* -ss->saveBuf.* (which is dead) - -in ssl3_sendPlainText - -ss->ssl3->current_write-> (spec) -ss->sec->writeBuf.* -ss->sec->isServer - -in SendBlock - -ss->sec->hash->length -ss->sec->blockSize -ss->sec->writeBuf.* -ss->sec->sendSecret -ss->sec->sendSequence -ss->sec->writecx * -ss->pendingBuf - --------------------------------------------------------------------------- - -Data variables (not const) protected by the "sslGlobalDataLock". -Note, this really should be a reader/writer lock. - -allowedByPolicy sslcon.c -maybeAllowedByPolicy sslcon.c -chosenPreference sslcon.c -policyWasSet sslcon.c - -cipherSuites[] ssl3con.c
diff --git a/net/third_party/nss/ssl/os2_err.c b/net/third_party/nss/ssl/os2_err.c deleted file mode 100644 index 6e3d423..0000000 --- a/net/third_party/nss/ssl/os2_err.c +++ /dev/null
@@ -1,330 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* - * This file essentially replicates NSPR's source for the functions that - * map system-specific error codes to NSPR error codes. We would use - * NSPR's functions, instead of duplicating them, but they're private. - * As long as SSL's server session cache code must do platform native I/O - * to accomplish its job, and NSPR's error mapping functions remain private, - * this code will continue to need to be replicated. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prerror.h" -#include "prlog.h" -#include <errno.h> - -/* - * Based on win32err.c - * OS2TODO Stub everything for now to build. HCT - */ - -/* forward declaration. */ -void nss_MD_os2_map_default_error(PRInt32 err); - -void -nss_MD_os2_map_opendir_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_closedir_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_readdir_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_delete_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -/* The error code for stat() is in errno. */ -void -nss_MD_os2_map_stat_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_fstat_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_rename_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -/* The error code for access() is in errno. */ -void -nss_MD_os2_map_access_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_mkdir_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_rmdir_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_read_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_transmitfile_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_write_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_lseek_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_fsync_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -/* - * For both CloseHandle() and closesocket(). - */ -void -nss_MD_os2_map_close_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_socket_error(PRInt32 err) -{ - // PR_ASSERT(err != WSANOTINITIALISED); - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_recv_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_recvfrom_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_send_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_sendto_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_accept_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break; - // case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_acceptex_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_connect_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEWOULDBLOCK: prError = PR_IN_PROGRESS_ERROR; break; - // case WSAEINVAL: prError = PR_ALREADY_INITIATED_ERROR; break; - // case WSAETIMEDOUT: prError = PR_IO_TIMEOUT_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_bind_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEINVAL: prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_listen_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break; - // case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_shutdown_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_getsockname_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_getpeername_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_getsockopt_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_setsockopt_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_open_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_gethostname_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -/* Win32 select() only works on sockets. So in this -** context, WSAENOTSOCK is equivalent to EBADF on Unix. -*/ -void -nss_MD_os2_map_select_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - // case WSAENOTSOCK: prError = PR_BAD_DESCRIPTOR_ERROR; break; - default: - nss_MD_os2_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_os2_map_lockf_error(PRInt32 err) -{ - nss_MD_os2_map_default_error(err); -} - -void -nss_MD_os2_map_default_error(PRInt32 err) -{ - PRErrorCode prError; - - switch (err) { -// case ENOENT: prError = PR_FILE_NOT_FOUND_ERROR; break; -// case ERROR_ACCESS_DENIED: prError = PR_NO_ACCESS_RIGHTS_ERROR; break; -// case ERROR_ALREADY_EXISTS: prError = PR_FILE_EXISTS_ERROR; break; -// case ERROR_DISK_CORRUPT: prError = PR_IO_ERROR; break; -// case ERROR_DISK_FULL: prError = PR_NO_DEVICE_SPACE_ERROR; break; -// case ERROR_DISK_OPERATION_FAILED: prError = PR_IO_ERROR; break; -// case ERROR_DRIVE_LOCKED: prError = PR_FILE_IS_LOCKED_ERROR; break; -// case ERROR_FILENAME_EXCED_RANGE: prError = PR_NAME_TOO_LONG_ERROR; break; -// case ERROR_FILE_CORRUPT: prError = PR_IO_ERROR; break; -// case ERROR_FILE_EXISTS: prError = PR_FILE_EXISTS_ERROR; break; -// case ERROR_FILE_INVALID: prError = PR_BAD_DESCRIPTOR_ERROR; break; -#if ERROR_FILE_NOT_FOUND != ENOENT -// case ERROR_FILE_NOT_FOUND: prError = PR_FILE_NOT_FOUND_ERROR; break; -#endif - default: - prError = PR_UNKNOWN_ERROR; - break; - } - PR_SetError(prError, err); -}
diff --git a/net/third_party/nss/ssl/os2_err.h b/net/third_party/nss/ssl/os2_err.h deleted file mode 100644 index 15e4741..0000000 --- a/net/third_party/nss/ssl/os2_err.h +++ /dev/null
@@ -1,53 +0,0 @@ -/* - * This file essentially replicates NSPR's source for the functions that - * map system-specific error codes to NSPR error codes. We would use - * NSPR's functions, instead of duplicating them, but they're private. - * As long as SSL's server session cache code must do platform native I/O - * to accomplish its job, and NSPR's error mapping functions remain private, - * This code will continue to need to be replicated. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* NSPR doesn't make these functions public, so we have to duplicate -** them in NSS. -*/ - -//HCT Based on Win32err.h -extern void nss_MD_os2_map_accept_error(PRInt32 err); -extern void nss_MD_os2_map_acceptex_error(PRInt32 err); -extern void nss_MD_os2_map_access_error(PRInt32 err); -extern void nss_MD_os2_map_bind_error(PRInt32 err); -extern void nss_MD_os2_map_close_error(PRInt32 err); -extern void nss_MD_os2_map_closedir_error(PRInt32 err); -extern void nss_MD_os2_map_connect_error(PRInt32 err); -extern void nss_MD_os2_map_default_error(PRInt32 err); -extern void nss_MD_os2_map_delete_error(PRInt32 err); -extern void nss_MD_os2_map_fstat_error(PRInt32 err); -extern void nss_MD_os2_map_fsync_error(PRInt32 err); -extern void nss_MD_os2_map_gethostname_error(PRInt32 err); -extern void nss_MD_os2_map_getpeername_error(PRInt32 err); -extern void nss_MD_os2_map_getsockname_error(PRInt32 err); -extern void nss_MD_os2_map_getsockopt_error(PRInt32 err); -extern void nss_MD_os2_map_listen_error(PRInt32 err); -extern void nss_MD_os2_map_lockf_error(PRInt32 err); -extern void nss_MD_os2_map_lseek_error(PRInt32 err); -extern void nss_MD_os2_map_mkdir_error(PRInt32 err); -extern void nss_MD_os2_map_open_error(PRInt32 err); -extern void nss_MD_os2_map_opendir_error(PRInt32 err); -extern void nss_MD_os2_map_read_error(PRInt32 err); -extern void nss_MD_os2_map_readdir_error(PRInt32 err); -extern void nss_MD_os2_map_recv_error(PRInt32 err); -extern void nss_MD_os2_map_recvfrom_error(PRInt32 err); -extern void nss_MD_os2_map_rename_error(PRInt32 err); -extern void nss_MD_os2_map_rmdir_error(PRInt32 err); -extern void nss_MD_os2_map_select_error(PRInt32 err); -extern void nss_MD_os2_map_send_error(PRInt32 err); -extern void nss_MD_os2_map_sendto_error(PRInt32 err); -extern void nss_MD_os2_map_setsockopt_error(PRInt32 err); -extern void nss_MD_os2_map_shutdown_error(PRInt32 err); -extern void nss_MD_os2_map_socket_error(PRInt32 err); -extern void nss_MD_os2_map_stat_error(PRInt32 err); -extern void nss_MD_os2_map_transmitfile_error(PRInt32 err); -extern void nss_MD_os2_map_write_error(PRInt32 err);
diff --git a/net/third_party/nss/ssl/preenc.h b/net/third_party/nss/ssl/preenc.h deleted file mode 100644 index bebff89e..0000000 --- a/net/third_party/nss/ssl/preenc.h +++ /dev/null
@@ -1,113 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ - -/* - * Fortezza support is removed. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Fortezza support is removed. - * This file remains so that old programs will continue to compile, - * But this functionality is no longer supported or implemented. - */ - -#include "seccomon.h" -#include "prio.h" - -typedef struct PEHeaderStr PEHeader; - -#define PE_MIME_TYPE "application/pre-encrypted" - -typedef struct PEFortezzaHeaderStr PEFortezzaHeader; -typedef struct PEFortezzaGeneratedHeaderStr PEFortezzaGeneratedHeader; -typedef struct PEFixedKeyHeaderStr PEFixedKeyHeader; -typedef struct PERSAKeyHeaderStr PERSAKeyHeader; - -struct PEFortezzaHeaderStr { - unsigned char key[12]; - unsigned char iv[24]; - unsigned char hash[20]; - unsigned char serial[8]; -}; - -struct PEFortezzaGeneratedHeaderStr { - unsigned char key[12]; - unsigned char iv[24]; - unsigned char hash[20]; - unsigned char Ra[128]; - unsigned char Y[128]; -}; - -struct PEFixedKeyHeaderStr { - unsigned char pkcs11Mech[4]; - unsigned char labelLen[2]; - unsigned char keyIDLen[2]; - unsigned char ivLen[2]; - unsigned char keyLen[2]; - unsigned char data[1]; -}; - -struct PERSAKeyHeaderStr { - unsigned char pkcs11Mech[4]; - unsigned char issuerLen[2]; - unsigned char serialLen[2]; - unsigned char ivLen[2]; - unsigned char keyLen[2]; - unsigned char data[1]; -}; - -#define PEFIXED_Label(header) (header->data) -#define PEFIXED_KeyID(header) (&header->data[GetInt2(header->labelLen)]) -#define PEFIXED_IV(header) (&header->data[GetInt2(header->labelLen) + \ - GetInt2(header->keyIDLen)]) -#define PEFIXED_Key(header) (&header->data[GetInt2(header->labelLen) + \ - GetInt2(header->keyIDLen) + \ - GetInt2(header->keyLen)]) -#define PERSA_Issuer(header) (header->data) -#define PERSA_Serial(header) (&header->data[GetInt2(header->issuerLen)]) -#define PERSA_IV(header) (&header->data[GetInt2(header->issuerLen) + \ - GetInt2(header->serialLen)]) -#define PERSA_Key(header) (&header->data[GetInt2(header->issuerLen) + \ - GetInt2(header->serialLen) + \ - GetInt2(header->keyLen)]) -struct PEHeaderStr { - unsigned char magic[2]; - unsigned char len[2]; - unsigned char type[2]; - unsigned char version[2]; - union { - PEFortezzaHeader fortezza; - PEFortezzaGeneratedHeader g_fortezza; - PEFixedKeyHeader fixed; - PERSAKeyHeader rsa; - } u; -}; - -#define PE_CRYPT_INTRO_LEN 8 -#define PE_INTRO_LEN 4 -#define PE_BASE_HEADER_LEN 8 - -#define PRE_BLOCK_SIZE 8 - -#define GetInt2(c) ((c[0] << 8) | c[1]) -#define GetInt4(c) (((unsigned long)c[0] << 24) | ((unsigned long)c[1] << 16) | \ - ((unsigned long)c[2] << 8) | ((unsigned long)c[3])) -#define PutInt2(c, i) ((c[1] = (i)&0xff), (c[0] = ((i) >> 8) & 0xff)) -#define PutInt4(c, i) ((c[0] = ((i) >> 24) & 0xff), (c[1] = ((i) >> 16) & 0xff), \ - (c[2] = ((i) >> 8) & 0xff), (c[3] = (i)&0xff)) - -#define PRE_MAGIC 0xc0de -#define PRE_VERSION 0x1010 -#define PRE_FORTEZZA_FILE 0x00ff -#define PRE_FORTEZZA_STREAM 0x00f5 -#define PRE_FORTEZZA_GEN_STREAM 0x00f6 -#define PRE_FIXED_FILE 0x000f -#define PRE_RSA_FILE 0x001f -#define PRE_FIXED_STREAM 0x0005 - -PEHeader *SSL_PreencryptedStreamToFile(PRFileDesc *fd, PEHeader *, - int *headerSize); - -PEHeader *SSL_PreencryptedFileToStream(PRFileDesc *fd, PEHeader *, - int *headerSize);
diff --git a/net/third_party/nss/ssl/prelib.c b/net/third_party/nss/ssl/prelib.c deleted file mode 100644 index 4db9ffe..0000000 --- a/net/third_party/nss/ssl/prelib.c +++ /dev/null
@@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ - -/* - * Functions used by https servers to send (download) pre-encrypted files - * over SSL connections that use Fortezza ciphersuites. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "cert.h" -#include "ssl.h" -#include "keyhi.h" -#include "secitem.h" -#include "sslimpl.h" -#include "pkcs11t.h" -#include "preenc.h" -#include "pk11func.h" - -PEHeader * -SSL_PreencryptedStreamToFile(PRFileDesc *fd, PEHeader *inHeader, - int *headerSize) -{ - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return NULL; -} - -PEHeader * -SSL_PreencryptedFileToStream(PRFileDesc *fd, PEHeader *header, - int *headerSize) -{ - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return NULL; -}
diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h deleted file mode 100644 index de5078b..0000000 --- a/net/third_party/nss/ssl/ssl.h +++ /dev/null
@@ -1,1302 +0,0 @@ -/* - * This file contains prototypes for the public SSL functions. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __ssl_h_ -#define __ssl_h_ - -#include "prtypes.h" -#include "prerror.h" -#include "prio.h" -#include "seccomon.h" -#include "cert.h" -#include "keyt.h" - -#include "sslt.h" /* public ssl data types */ - -#if defined(_WIN32) && !defined(IN_LIBSSL) && !defined(NSS_USE_STATIC_LIBS) -#define SSL_IMPORT extern __declspec(dllimport) -#else -#define SSL_IMPORT extern -#endif - -SEC_BEGIN_PROTOS - -/* constant table enumerating all implemented SSL 2 and 3 cipher suites. */ -SSL_IMPORT const PRUint16 SSL_ImplementedCiphers[]; - -/* the same as the above, but is a function */ -SSL_IMPORT const PRUint16 *SSL_GetImplementedCiphers(void); - -/* number of entries in the above table. */ -SSL_IMPORT const PRUint16 SSL_NumImplementedCiphers; - -/* the same as the above, but is a function */ -SSL_IMPORT PRUint16 SSL_GetNumImplementedCiphers(void); - -/* Macro to tell which ciphers in table are SSL2 vs SSL3/TLS. */ -#define SSL_IS_SSL2_CIPHER(which) (((which)&0xfff0) == 0xff00) - -/* -** Imports fd into SSL, returning a new socket. Copies SSL configuration -** from model. -*/ -SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); - -/* -** Imports fd into DTLS, returning a new socket. Copies DTLS configuration -** from model. -*/ -SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); - -/* -** Enable/disable an ssl mode -** -** SSL_SECURITY: -** enable/disable use of SSL security protocol before connect -** -** SSL_SOCKS: -** enable/disable use of socks before connect -** (No longer supported). -** -** SSL_REQUEST_CERTIFICATE: -** require a certificate during secure connect -*/ -/* options */ -#define SSL_SECURITY 1 /* (on by default) */ -#define SSL_SOCKS 2 /* (off by default) */ -#define SSL_REQUEST_CERTIFICATE 3 /* (off by default) */ -#define SSL_HANDSHAKE_AS_CLIENT 5 /* force accept to hs as client */ - /* (off by default) */ -#define SSL_HANDSHAKE_AS_SERVER 6 /* force connect to hs as server */ - /* (off by default) */ - -/* OBSOLETE: SSL v2 is obsolete and may be removed soon. */ -#define SSL_ENABLE_SSL2 7 /* enable ssl v2 (off by default) */ - -/* OBSOLETE: See "SSL Version Range API" below for the replacement and a -** description of the non-obvious semantics of using SSL_ENABLE_SSL3. -*/ -#define SSL_ENABLE_SSL3 8 /* enable ssl v3 (on by default) */ - -#define SSL_NO_CACHE 9 /* don't use the session cache */ - /* (off by default) */ -#define SSL_REQUIRE_CERTIFICATE 10 /* (SSL_REQUIRE_FIRST_HANDSHAKE */ - /* by default) */ -#define SSL_ENABLE_FDX 11 /* permit simultaneous read/write */ - /* (off by default) */ - -/* OBSOLETE: SSL v2 compatible hellos are not accepted by some TLS servers -** and cannot negotiate extensions. SSL v2 is obsolete. This option may be -** removed soon. -*/ -#define SSL_V2_COMPATIBLE_HELLO 12 /* send v3 client hello in v2 fmt */ - /* (off by default) */ - -/* OBSOLETE: See "SSL Version Range API" below for the replacement and a -** description of the non-obvious semantics of using SSL_ENABLE_TLS. -*/ -#define SSL_ENABLE_TLS 13 /* enable TLS (on by default) */ - -#define SSL_ROLLBACK_DETECTION 14 /* for compatibility, default: on */ -#define SSL_NO_STEP_DOWN 15 /* Disable export cipher suites */ - /* if step-down keys are needed. */ - /* default: off, generate */ - /* step-down keys if needed. */ -#define SSL_BYPASS_PKCS11 16 /* use PKCS#11 for pub key only */ -#define SSL_NO_LOCKS 17 /* Don't use locks for protection */ -#define SSL_ENABLE_SESSION_TICKETS 18 /* Enable TLS SessionTicket */ - /* extension (off by default) */ -#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */ - /* DEFLATE (off by default) */ -#define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */ -#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */ - /* Cipher Suite Value (SCSV) or */ - /* Renegotiation Info (RI) */ - /* extension in ALL handshakes. */ - /* default: off */ -#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */ - /* default, applies only to */ - /* clients). False start is a */ -/* mode where an SSL client will start sending application data before - * verifying the server's Finished message. This means that we could end up - * sending data to an imposter. However, the data will be encrypted and - * only the true server can derive the session key. Thus, so long as the - * cipher isn't broken this is safe. The advantage of false start is that - * it saves a round trip for client-speaks-first protocols when performing a - * full handshake. - * - * In addition to enabling this option, the application must register a - * callback using the SSL_SetCanFalseStartCallback function. - */ - -/* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks - * on SSL CBC mode cipher suites (see RFC 4346 Section F.3) by splitting - * non-empty application_data records into two records; the first record has - * only the first byte of plaintext, and the second has the rest. - * - * This only prevents the attack in the sending direction; the connection may - * still be vulnerable to such attacks if the peer does not implement a similar - * countermeasure. - * - * This protection mechanism is on by default; the default can be overridden by - * setting NSS_SSL_CBC_RANDOM_IV=0 in the environment prior to execution, - * and/or by the application setting the option SSL_CBC_RANDOM_IV to PR_FALSE. - * - * The per-record IV in TLS 1.1 and later adds one block of overhead per - * record, whereas this hack will add at least two blocks of overhead per - * record, so TLS 1.1+ will always be more efficient. - * - * Other implementations (e.g. some versions of OpenSSL, in some - * configurations) prevent the same attack by prepending an empty - * application_data record to every application_data record they send; we do - * not do that because some implementations cannot handle empty - * application_data records. Also, we only split application_data records and - * not other types of records, because some implementations will not accept - * fragmented records of some other types (e.g. some versions of NSS do not - * accept fragmented alerts). - */ -#define SSL_CBC_RANDOM_IV 23 -#define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */ - -/* SSL_ENABLE_NPN controls whether the NPN extension is enabled for the initial - * handshake when application layer protocol negotiation is used. - * SSL_SetNextProtoCallback or SSL_SetNextProtoNego must be used to control the - * application layer protocol negotiation; otherwise, the NPN extension will - * not be negotiated. SSL_ENABLE_NPN is currently enabled by default but this - * may change in future versions. - */ -#define SSL_ENABLE_NPN 25 - -/* SSL_ENABLE_ALPN controls whether the ALPN extension is enabled for the - * initial handshake when application layer protocol negotiation is used. - * SSL_SetNextProtoNego (not SSL_SetNextProtoCallback) must be used to control - * the application layer protocol negotiation; otherwise, the ALPN extension - * will not be negotiated. ALPN is not negotiated for renegotiation handshakes, - * even though the ALPN specification defines a way to use ALPN during - * renegotiations. SSL_ENABLE_ALPN is currently disabled by default, but this - * may change in future versions. - */ -#define SSL_ENABLE_ALPN 26 - -/* SSL_REUSE_SERVER_ECDHE_KEY controls whether the ECDHE server key is - * reused for multiple handshakes or generated each time. - * SSL_REUSE_SERVER_ECDHE_KEY is currently enabled by default. - * This socket option is for ECDHE, only. It is unrelated to DHE. - */ -#define SSL_REUSE_SERVER_ECDHE_KEY 27 - -#define SSL_ENABLE_FALLBACK_SCSV 28 /* Send fallback SCSV in \ - * handshakes. */ - -/* SSL_ENABLE_SERVER_DHE controls whether DHE is enabled for the server socket. - */ -#define SSL_ENABLE_SERVER_DHE 29 - -/* Use draft-ietf-tls-session-hash. Controls whether we offer the - * extended_master_secret extension which, when accepted, hashes - * the handshake transcript into the master secret. This option is - * disabled by default. - */ -#define SSL_ENABLE_EXTENDED_MASTER_SECRET 30 - -/* Request Signed Certificate Timestamps via TLS extension (client) */ -#define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 31 - -#ifdef SSL_DEPRECATED_FUNCTION -/* Old deprecated function names */ -SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on); -SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on); -#endif - -/* New function names */ -SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRBool on); -SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRBool *on); -SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRBool on); -SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRBool *on); -SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle); - -/* SSLNextProtoCallback is called during the handshake for the client, when a - * Next Protocol Negotiation (NPN) extension has been received from the server. - * |protos| and |protosLen| define a buffer which contains the server's - * advertisement. This data is guaranteed to be well formed per the NPN spec. - * |protoOut| is a buffer provided by the caller, of length 255 (the maximum - * allowed by the protocol). On successful return, the protocol to be announced - * to the server will be in |protoOut| and its length in |*protoOutLen|. - * - * The callback must return SECFailure or SECSuccess (not SECWouldBlock). - */ -typedef SECStatus(PR_CALLBACK *SSLNextProtoCallback)( - void *arg, - PRFileDesc *fd, - const unsigned char *protos, - unsigned int protosLen, - unsigned char *protoOut, - unsigned int *protoOutLen, - unsigned int protoMaxOut); - -/* SSL_SetNextProtoCallback sets a callback function to handle Next Protocol - * Negotiation. It causes a client to advertise NPN. */ -SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd, - SSLNextProtoCallback callback, - void *arg); - -/* SSL_SetNextProtoNego can be used as an alternative to - * SSL_SetNextProtoCallback. It also causes a client to advertise NPN and - * installs a default callback function which selects the first supported - * protocol in server-preference order. If no matching protocol is found it - * selects the first supported protocol. - * - * Using this function also allows the client to transparently support ALPN. - * The same set of protocols will be advertised via ALPN and, if the server - * uses ALPN to select a protocol, SSL_GetNextProto will return - * SSL_NEXT_PROTO_SELECTED as the state. - * - * Since NPN uses the first protocol as the fallback protocol, when sending an - * ALPN extension, the first protocol is moved to the end of the list. This - * indicates that the fallback protocol is the least preferred. The other - * protocols should be in preference order. - * - * The supported protocols are specified in |data| in wire-format (8-bit - * length-prefixed). For example: "\010http/1.1\006spdy/2". */ -SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd, - const unsigned char *data, - unsigned int length); - -typedef enum SSLNextProtoState { - SSL_NEXT_PROTO_NO_SUPPORT = 0, /* No peer support */ - SSL_NEXT_PROTO_NEGOTIATED = 1, /* Mutual agreement */ - SSL_NEXT_PROTO_NO_OVERLAP = 2, /* No protocol overlap found */ - SSL_NEXT_PROTO_SELECTED = 3 /* Server selected proto (ALPN) */ -} SSLNextProtoState; - -/* SSL_GetNextProto can be used in the HandshakeCallback or any time after - * a handshake to retrieve the result of the Next Protocol negotiation. - * - * The length of the negotiated protocol, if any, is written into *bufLen. - * If the negotiated protocol is longer than bufLenMax, then SECFailure is - * returned. Otherwise, the negotiated protocol, if any, is written into buf, - * and SECSuccess is returned. */ -SSL_IMPORT SECStatus SSL_GetNextProto(PRFileDesc *fd, - SSLNextProtoState *state, - unsigned char *buf, - unsigned int *bufLen, - unsigned int bufLenMax); - -/* -** Control ciphers that SSL uses. If on is non-zero then the named cipher -** is enabled, otherwise it is disabled. -** The "cipher" values are defined in sslproto.h (the SSL_EN_* values). -** EnableCipher records user preferences. -** SetPolicy sets the policy according to the policy module. -*/ -#ifdef SSL_DEPRECATED_FUNCTION -/* Old deprecated function names */ -SSL_IMPORT SECStatus SSL_EnableCipher(long which, PRBool enabled); -SSL_IMPORT SECStatus SSL_SetPolicy(long which, int policy); -#endif - -/* New function names */ -SSL_IMPORT SECStatus SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 cipher, PRBool enabled); -SSL_IMPORT SECStatus SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 cipher, PRBool *enabled); -SSL_IMPORT SECStatus SSL_CipherPrefSetDefault(PRInt32 cipher, PRBool enabled); -SSL_IMPORT SECStatus SSL_CipherPrefGetDefault(PRInt32 cipher, PRBool *enabled); -SSL_IMPORT SECStatus SSL_CipherPolicySet(PRInt32 cipher, PRInt32 policy); -SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy); - -/* -** Control for TLS signature algorithms for TLS 1.2 only. -** -** This governs what signature algorithms are sent by a client in the -** signature_algorithms extension. A client will not accept a signature from a -** server unless it uses an enabled algorithm. -** -** This also governs what the server sends in the supported_signature_algorithms -** field of a CertificateRequest. It also changes what the server uses to sign -** ServerKeyExchange: a server uses the first entry from this list that is -** compatible with the client's advertised signature_algorithms extension and -** the selected server certificate. -** -** Omitting SHA-256 from this list might be foolish. Support is mandatory in -** TLS 1.2 and there might be interoperability issues. For a server, NSS only -** supports SHA-256 for verifying a TLS 1.2 CertificateVerify. This list needs -** to include SHA-256 if client authentication is requested or required, or -** creating a CertificateRequest will fail. -*/ -SSL_IMPORT SECStatus SSL_SignaturePrefSet( - PRFileDesc *fd, const SSLSignatureAndHashAlg *algorithms, - unsigned int count); - -/* -** Get the currently configured signature algorithms. -** -** The algorithms are written to |algorithms| but not if there are more than -** |maxCount| values configured. The number of algorithms that are in use are -** written to |count|. This fails if |maxCount| is insufficiently large. -*/ -SSL_IMPORT SECStatus SSL_SignaturePrefGet( - PRFileDesc *fd, SSLSignatureAndHashAlg *algorithms, unsigned int *count, - unsigned int maxCount); - -/* -** Returns the maximum number of signature algorithms that are supported and -** can be set or retrieved using SSL_SignaturePrefSet or SSL_SignaturePrefGet. -*/ -SSL_IMPORT unsigned int SSL_SignatureMaxCount(); - -/* SSL_DHEGroupPrefSet is used to configure the set of allowed/enabled DHE group -** parameters that can be used by NSS for the given server socket. -** The first item in the array is used as the default group, if no other -** selection criteria can be used by NSS. -** The set is provided as an array of identifiers as defined by SSLDHEGroupType. -** If more than one group identifier is provided, NSS will select the one to use. -** For example, a TLS extension sent by the client might indicate a preference. -*/ -SSL_IMPORT SECStatus SSL_DHEGroupPrefSet(PRFileDesc *fd, - SSLDHEGroupType *groups, - PRUint16 num_groups); - -/* Enable the use of a DHE group that's smaller than the library default, -** for backwards compatibility reasons. The DH parameters will be created -** at the time this function is called, which might take a very long time. -** The function will block until generation is completed. -** The intention is to enforce that fresh and safe parameters are generated -** each time a process is started. -** At the time this API was initially implemented, the API will enable the -** use of 1024 bit DHE parameters. This value might get increased in future -** versions of NSS. -** -** It is allowed to call this API will a NULL value for parameter fd, -** which will prepare the global parameters that NSS will reuse for the remainder -** of the process lifetime. This can be used early after startup of a process, -** to avoid a delay when handling incoming client connections. -** This preparation with a NULL for parameter fd will NOT enable the weak group -** on sockets. The function needs to be called again for every socket that -** should use the weak group. -** -** It is allowed to use this API in combination with the SSL_DHEGroupPrefSet API. -** If both APIs have been called, the weakest group will be used, -** unless it is certain that the client supports larger group parameters. -** The weak group will be used as the default group, overriding the preference -** for the first group potentially set with a call to SSL_DHEGroupPrefSet -** (The first group set using SSL_DHEGroupPrefSet will still be enabled, but -** it's no longer the default group.) -*/ -SSL_IMPORT SECStatus SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled); - -/* SSL_CipherOrderSet sets the cipher suite preference order from |ciphers|, - * which must be an array of cipher suite ids of length |len|. All the given - * cipher suite ids must appear in the array that is returned by - * |SSL_GetImplementedCiphers| and may only appear once, at most. */ -SSL_IMPORT SECStatus SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, - unsigned int len); - -/* SSLChannelBindingType enumerates the types of supported channel binding - * values. See RFC 5929. */ -typedef enum SSLChannelBindingType { - SSL_CHANNEL_BINDING_TLS_UNIQUE = 1, -} SSLChannelBindingType; - -/* SSL_GetChannelBinding copies the requested channel binding value, as defined - * in RFC 5929, into |out|. The full length of the binding value is written - * into |*outLen|. - * - * At most |outLenMax| bytes of data are copied. If |outLenMax| is - * insufficient then the function returns SECFailure and sets the error to - * SEC_ERROR_OUTPUT_LEN, but |*outLen| is still set. - * - * This call will fail if made during a renegotiation. */ -SSL_IMPORT SECStatus SSL_GetChannelBinding(PRFileDesc *fd, - SSLChannelBindingType binding_type, - unsigned char *out, - unsigned int *outLen, - unsigned int outLenMax); - -/* SSL Version Range API -** -** This API should be used to control SSL 3.0 & TLS support instead of the -** older SSL_Option* API; however, the SSL_Option* API MUST still be used to -** control SSL 2.0 support. In this version of libssl, SSL 3.0 and TLS 1.0 are -** enabled by default. Future versions of libssl may change which versions of -** the protocol are enabled by default. -** -** The SSLProtocolVariant enum indicates whether the protocol is of type -** stream or datagram. This must be provided to the functions that do not -** take an fd. Functions which take an fd will get the variant from the fd, -** which is typed. -** -** Using the new version range API in conjunction with the older -** SSL_OptionSet-based API for controlling the enabled protocol versions may -** cause unexpected results. Going forward, we guarantee only the following: -** -** SSL_OptionGet(SSL_ENABLE_TLS) will return PR_TRUE if *ANY* versions of TLS -** are enabled. -** -** SSL_OptionSet(SSL_ENABLE_TLS, PR_FALSE) will disable *ALL* versions of TLS, -** including TLS 1.0 and later. -** -** The above two properties provide compatibility for applications that use -** SSL_OptionSet to implement the insecure fallback from TLS 1.x to SSL 3.0. -** -** SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE) will enable TLS 1.0, and may also -** enable some later versions of TLS, if it is necessary to do so in order to -** keep the set of enabled versions contiguous. For example, if TLS 1.2 is -** enabled, then after SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE), TLS 1.0, -** TLS 1.1, and TLS 1.2 will be enabled, and the call will have no effect on -** whether SSL 3.0 is enabled. If no later versions of TLS are enabled at the -** time SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE) is called, then no later -** versions of TLS will be enabled by the call. -** -** SSL_OptionSet(SSL_ENABLE_SSL3, PR_FALSE) will disable SSL 3.0, and will not -** change the set of TLS versions that are enabled. -** -** SSL_OptionSet(SSL_ENABLE_SSL3, PR_TRUE) will enable SSL 3.0, and may also -** enable some versions of TLS if TLS 1.1 or later is enabled at the time of -** the call, the same way SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE) works, in -** order to keep the set of enabled versions contiguous. -*/ - -/* Returns, in |*vrange|, the range of SSL3/TLS versions supported for the -** given protocol variant by the version of libssl linked-to at runtime. -*/ -SSL_IMPORT SECStatus SSL_VersionRangeGetSupported( - SSLProtocolVariant protocolVariant, SSLVersionRange *vrange); - -/* Returns, in |*vrange|, the range of SSL3/TLS versions enabled by default -** for the given protocol variant. -*/ -SSL_IMPORT SECStatus SSL_VersionRangeGetDefault( - SSLProtocolVariant protocolVariant, SSLVersionRange *vrange); - -/* Sets the range of enabled-by-default SSL3/TLS versions for the given -** protocol variant to |*vrange|. -*/ -SSL_IMPORT SECStatus SSL_VersionRangeSetDefault( - SSLProtocolVariant protocolVariant, const SSLVersionRange *vrange); - -/* Returns, in |*vrange|, the range of enabled SSL3/TLS versions for |fd|. */ -SSL_IMPORT SECStatus SSL_VersionRangeGet(PRFileDesc *fd, - SSLVersionRange *vrange); - -/* Sets the range of enabled SSL3/TLS versions for |fd| to |*vrange|. */ -SSL_IMPORT SECStatus SSL_VersionRangeSet(PRFileDesc *fd, - const SSLVersionRange *vrange); - -/* Sets the version to check the server random against for the - * fallback check defined in [draft-ietf-tls-tls13-11 Section 6.3.1.1]. - * This function is provided to allow for detection of forced downgrade - * attacks against client-side reconnect-and-fallback outside of TLS - * by setting |version| to be that of the original connection, rather - * than that of the new connection. - * - * The default, which can also be enabled by setting |version| to - * zero, is just to check against the max version in the - * version range (see SSL_VersionRangeSet). */ -SSL_IMPORT SECStatus SSL_SetDowngradeCheckVersion(PRFileDesc *fd, - PRUint16 version); - -/* Values for "policy" argument to SSL_CipherPolicySet */ -/* Values returned by SSL_CipherPolicyGet. */ -#define SSL_NOT_ALLOWED 0 /* or invalid or unimplemented */ -#define SSL_ALLOWED 1 -#define SSL_RESTRICTED 2 /* only with "Step-Up" certs. */ - -/* Values for "on" with SSL_REQUIRE_CERTIFICATE. */ -#define SSL_REQUIRE_NEVER ((PRBool)0) -#define SSL_REQUIRE_ALWAYS ((PRBool)1) -#define SSL_REQUIRE_FIRST_HANDSHAKE ((PRBool)2) -#define SSL_REQUIRE_NO_ERROR ((PRBool)3) - -/* Values for "on" with SSL_ENABLE_RENEGOTIATION */ -/* Never renegotiate at all. */ -#define SSL_RENEGOTIATE_NEVER ((PRBool)0) -/* Renegotiate without restriction, whether or not the peer's client hello */ -/* bears the renegotiation info extension. Vulnerable, as in the past. */ -#define SSL_RENEGOTIATE_UNRESTRICTED ((PRBool)1) -/* Only renegotiate if the peer's hello bears the TLS renegotiation_info */ -/* extension. This is safe renegotiation. */ -#define SSL_RENEGOTIATE_REQUIRES_XTN ((PRBool)2) -/* Disallow unsafe renegotiation in server sockets only, but allow clients */ -/* to continue to renegotiate with vulnerable servers. */ -/* This value should only be used during the transition period when few */ -/* servers have been upgraded. */ -#define SSL_RENEGOTIATE_TRANSITIONAL ((PRBool)3) - -/* -** Reset the handshake state for fd. This will make the complete SSL -** handshake protocol execute from the ground up on the next i/o -** operation. -*/ -SSL_IMPORT SECStatus SSL_ResetHandshake(PRFileDesc *fd, PRBool asServer); - -/* -** Force the handshake for fd to complete immediately. This blocks until -** the complete SSL handshake protocol is finished. -*/ -SSL_IMPORT SECStatus SSL_ForceHandshake(PRFileDesc *fd); - -/* -** Same as above, but with an I/O timeout. - */ -SSL_IMPORT SECStatus SSL_ForceHandshakeWithTimeout(PRFileDesc *fd, - PRIntervalTime timeout); - -SSL_IMPORT SECStatus SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain); - -/* -** Query security status of socket. *on is set to one if security is -** enabled. *keySize will contain the stream key size used. *issuer will -** contain the RFC1485 verison of the name of the issuer of the -** certificate at the other end of the connection. For a client, this is -** the issuer of the server's certificate; for a server, this is the -** issuer of the client's certificate (if any). Subject is the subject of -** the other end's certificate. The pointers can be zero if the desired -** data is not needed. All strings returned by this function are owned -** by the caller, and need to be freed with PORT_Free. -*/ -SSL_IMPORT SECStatus SSL_SecurityStatus(PRFileDesc *fd, int *on, char **cipher, - int *keySize, int *secretKeySize, - char **issuer, char **subject); - -/* Values for "on" */ -#define SSL_SECURITY_STATUS_NOOPT -1 -#define SSL_SECURITY_STATUS_OFF 0 -#define SSL_SECURITY_STATUS_ON_HIGH 1 -#define SSL_SECURITY_STATUS_ON_LOW 2 -#define SSL_SECURITY_STATUS_FORTEZZA 3 /* NO LONGER SUPPORTED */ - -/* -** Return the certificate for our SSL peer. If the client calls this -** it will always return the server's certificate. If the server calls -** this, it may return NULL if client authentication is not enabled or -** if the client had no certificate when asked. -** "fd" the socket "file" descriptor -*/ -SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd); - -/* -** Return the certificates presented by the SSL peer. If the SSL peer -** did not present certificates, return NULL with the -** SSL_ERROR_NO_CERTIFICATE error. On failure, return NULL with an error -** code other than SSL_ERROR_NO_CERTIFICATE. -** "fd" the socket "file" descriptor -*/ -SSL_IMPORT CERTCertList *SSL_PeerCertificateChain(PRFileDesc *fd); - -/* SSL_PeerStapledOCSPResponses returns the OCSP responses that were provided - * by the TLS server. The return value is a pointer to an internal SECItemArray - * that contains the returned OCSP responses; it is only valid until the - * callback function that calls SSL_PeerStapledOCSPResponses returns. - * - * If no OCSP responses were given by the server then the result will be empty. - * If there was an error, then the result will be NULL. - * - * You must set the SSL_ENABLE_OCSP_STAPLING option to enable OCSP stapling. - * to be provided by a server. - * - * libssl does not do any validation of the OCSP response itself; the - * authenticate certificate hook is responsible for doing so. The default - * authenticate certificate hook, SSL_AuthCertificate, does not implement - * any OCSP stapling funtionality, but this may change in future versions. - */ -SSL_IMPORT const SECItemArray *SSL_PeerStapledOCSPResponses(PRFileDesc *fd); - -/* SSL_PeerSignedCertTimestamps returns the signed_certificate_timestamp - * extension data provided by the TLS server. The return value is a pointer - * to an internal SECItem that contains the returned response (as a serialized - * SignedCertificateTimestampList, see RFC 6962). The returned pointer is only - * valid until the callback function that calls SSL_PeerSignedCertTimestamps - * (e.g. the authenticate certificate hook, or the handshake callback) returns. - * - * If no Signed Certificate Timestamps were given by the server then the result - * will be empty. If there was an error, then the result will be NULL. - * - * You must set the SSL_ENABLE_SIGNED_CERT_TIMESTAMPS option to indicate support - * for Signed Certificate Timestamps to a server. - * - * libssl does not do any parsing or validation of the response itself. - */ -SSL_IMPORT const SECItem *SSL_PeerSignedCertTimestamps(PRFileDesc *fd); - -/* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses - * in the fd's data, which may be sent as part of a server side cert_status - * handshake message. Parameter |responses| is for the server certificate of - * the key exchange type |kea|. - * The function will duplicate the responses array. - */ -SSL_IMPORT SECStatus -SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, - SSLKEAType kea); - -/* - * SSL_SetSignedCertTimestamps stores serialized signed_certificate_timestamp - * extension data in the fd. The signed_certificate_timestamp data is sent - * during the handshake (if requested by the client). Parameter |scts| - * is for the server certificate of the key exchange type |kea|. - * The function will duplicate the provided data item. To clear previously - * set data for a given key exchange type |kea|, pass NULL to |scts|. - */ -SSL_IMPORT SECStatus -SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, - SSLKEAType kea); - -/* -** Authenticate certificate hook. Called when a certificate comes in -** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the -** certificate. -** -** The authenticate certificate hook must return SECSuccess to indicate the -** certificate is valid, SECFailure to indicate the certificate is invalid, -** or SECWouldBlock if the application will authenticate the certificate -** asynchronously. SECWouldBlock is only supported for non-blocking sockets. -** -** If the authenticate certificate hook returns SECFailure, then the bad cert -** hook will be called. The bad cert handler is NEVER called if the -** authenticate certificate hook returns SECWouldBlock. If the application -** needs to handle and/or override a bad cert, it should do so before it -** calls SSL_AuthCertificateComplete (modifying the error it passes to -** SSL_AuthCertificateComplete as needed). -** -** See the documentation for SSL_AuthCertificateComplete for more information -** about the asynchronous behavior that occurs when the authenticate -** certificate hook returns SECWouldBlock. -** -** RFC 6066 says that clients should send the bad_certificate_status_response -** alert when they encounter an error processing the stapled OCSP response. -** libssl does not provide a way for the authenticate certificate hook to -** indicate that an OCSP error (SEC_ERROR_OCSP_*) that it returns is an error -** in the stapled OCSP response or an error in some other OCSP response. -** Further, NSS does not provide a convenient way to control or determine -** which OCSP response(s) were used to validate a certificate chain. -** Consequently, the current version of libssl does not ever send the -** bad_certificate_status_response alert. This may change in future releases. -*/ -typedef SECStatus(PR_CALLBACK *SSLAuthCertificate)(void *arg, PRFileDesc *fd, - PRBool checkSig, - PRBool isServer); - -SSL_IMPORT SECStatus SSL_AuthCertificateHook(PRFileDesc *fd, - SSLAuthCertificate f, - void *arg); - -/* An implementation of the certificate authentication hook */ -SSL_IMPORT SECStatus SSL_AuthCertificate(void *arg, PRFileDesc *fd, - PRBool checkSig, PRBool isServer); - -/* - * Prototype for SSL callback to get client auth data from the application. - * arg - application passed argument - * caNames - pointer to distinguished names of CAs that the server likes - * pRetCert - pointer to pointer to cert, for return of cert - * pRetKey - pointer to key pointer, for return of key - */ -typedef SECStatus(PR_CALLBACK *SSLGetClientAuthData)(void *arg, - PRFileDesc *fd, - CERTDistNames *caNames, - CERTCertificate **pRetCert, /*return */ - SECKEYPrivateKey **pRetKey); /* return */ - -/* - * Set the client side callback for SSL to retrieve user's private key - * and certificate. - * fd - the file descriptor for the connection in question - * f - the application's callback that delivers the key and cert - * a - application specific data - */ -SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, - SSLGetClientAuthData f, void *a); - -/* -** SNI extension processing callback function. -** It is called when SSL socket receives SNI extension in ClientHello message. -** Upon this callback invocation, application is responsible to reconfigure the -** socket with the data for a particular server name. -** There are three potential outcomes of this function invocation: -** * application does not recognize the name or the type and wants the -** "unrecognized_name" alert be sent to the client. In this case the callback -** function must return SSL_SNI_SEND_ALERT status. -** * application does not recognize the name, but wants to continue with -** the handshake using the current socket configuration. In this case, -** no socket reconfiguration is needed and the function should return -** SSL_SNI_CURRENT_CONFIG_IS_USED. -** * application recognizes the name and reconfigures the socket with -** appropriate certs, key, etc. There are many ways to reconfigure. NSS -** provides SSL_ReconfigFD function that can be used to update the socket -** data from model socket. To continue with the rest of the handshake, the -** implementation function should return an index of a name it has chosen. -** LibSSL will ignore any SNI extension received in a ClientHello message -** if application does not register a SSLSNISocketConfig callback. -** Each type field of SECItem indicates the name type. -** NOTE: currently RFC3546 defines only one name type: sni_host_name. -** Client is allowed to send only one name per known type. LibSSL will -** send an "unrecognized_name" alert if SNI extension name list contains more -** then one name of a type. -*/ -typedef PRInt32(PR_CALLBACK *SSLSNISocketConfig)(PRFileDesc *fd, - const SECItem *srvNameArr, - PRUint32 srvNameArrSize, - void *arg); - -/* -** SSLSNISocketConfig should return an index within 0 and srvNameArrSize-1 -** when it has reconfigured the socket fd to use certs and keys, etc -** for a specific name. There are two other allowed return values. One -** tells libSSL to use the default cert and key. The other tells libSSL -** to send the "unrecognized_name" alert. These values are: -**/ -#define SSL_SNI_CURRENT_CONFIG_IS_USED -1 -#define SSL_SNI_SEND_ALERT -2 - -/* -** Set application implemented SNISocketConfig callback. -*/ -SSL_IMPORT SECStatus SSL_SNISocketConfigHook(PRFileDesc *fd, - SSLSNISocketConfig f, - void *arg); - -/* -** Reconfigure fd SSL socket with model socket parameters. Sets -** server certs and keys, list of trust anchor, socket options -** and all SSL socket call backs and parameters. -*/ -SSL_IMPORT PRFileDesc *SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd); - -/* - * Set the client side argument for SSL to retrieve PKCS #11 pin. - * fd - the file descriptor for the connection in question - * a - pkcs11 application specific data - */ -SSL_IMPORT SECStatus SSL_SetPKCS11PinArg(PRFileDesc *fd, void *a); - -/* -** This is a callback for dealing with server certs that are not authenticated -** by the client. The client app can decide that it actually likes the -** cert by some external means and restart the connection. -** -** The bad cert hook must return SECSuccess to override the result of the -** authenticate certificate hook, SECFailure if the certificate should still be -** considered invalid, or SECWouldBlock if the application will authenticate -** the certificate asynchronously. SECWouldBlock is only supported for -** non-blocking sockets. -** -** See the documentation for SSL_AuthCertificateComplete for more information -** about the asynchronous behavior that occurs when the bad cert hook returns -** SECWouldBlock. -*/ -typedef SECStatus(PR_CALLBACK *SSLBadCertHandler)(void *arg, PRFileDesc *fd); -SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, - void *arg); - -/* -** Configure SSL socket for running a secure server. Needs the -** certificate for the server and the servers private key. The arguments -** are copied. -*/ -SSL_IMPORT SECStatus SSL_ConfigSecureServer( - PRFileDesc *fd, CERTCertificate *cert, - SECKEYPrivateKey *key, SSLKEAType kea); - -/* -** Allows SSL socket configuration with caller-supplied certificate chain. -** If certChainOpt is NULL, tries to find one. -*/ -SSL_IMPORT SECStatus -SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, - const CERTCertificateList *certChainOpt, - SECKEYPrivateKey *key, SSLKEAType kea); - -/* -** Configure a secure server's session-id cache. Define the maximum number -** of entries in the cache, the longevity of the entires, and the directory -** where the cache files will be placed. These values can be zero, and -** if so, the implementation will choose defaults. -** This version of the function is for use in applications that have only one -** process that uses the cache (even if that process has multiple threads). -*/ -SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCache(int maxCacheEntries, - PRUint32 timeout, - PRUint32 ssl3_timeout, - const char *directory); - -/* Configure a secure server's session-id cache. Depends on value of - * enableMPCache, configures malti-proc or single proc cache. */ -SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCacheWithOpt( - PRUint32 timeout, - PRUint32 ssl3_timeout, - const char *directory, - int maxCacheEntries, - int maxCertCacheEntries, - int maxSrvNameCacheEntries, - PRBool enableMPCache); - -/* -** Like SSL_ConfigServerSessionIDCache, with one important difference. -** If the application will run multiple processes (as opposed to, or in -** addition to multiple threads), then it must call this function, instead -** of calling SSL_ConfigServerSessionIDCache(). -** This has nothing to do with the number of processORs, only processEs. -** This function sets up a Server Session ID (SID) cache that is safe for -** access by multiple processes on the same system. -*/ -SSL_IMPORT SECStatus SSL_ConfigMPServerSIDCache(int maxCacheEntries, - PRUint32 timeout, - PRUint32 ssl3_timeout, - const char *directory); - -/* Get and set the configured maximum number of mutexes used for the -** server's store of SSL sessions. This value is used by the server -** session ID cache initialization functions shown above. Note that on -** some platforms, these mutexes are actually implemented with POSIX -** semaphores, or with unnamed pipes. The default value varies by platform. -** An attempt to set a too-low maximum will return an error and the -** configured value will not be changed. -*/ -SSL_IMPORT PRUint32 SSL_GetMaxServerCacheLocks(void); -SSL_IMPORT SECStatus SSL_SetMaxServerCacheLocks(PRUint32 maxLocks); - -/* environment variable set by SSL_ConfigMPServerSIDCache, and queried by - * SSL_InheritMPServerSIDCache when envString is NULL. - */ -#define SSL_ENV_VAR_NAME "SSL_INHERITANCE" - -/* called in child to inherit SID Cache variables. - * If envString is NULL, this function will use the value of the environment - * variable "SSL_INHERITANCE", otherwise the string value passed in will be - * used. - */ -SSL_IMPORT SECStatus SSL_InheritMPServerSIDCache(const char *envString); - -/* -** Set the callback that gets called when a TLS handshake is complete. The -** handshake callback is called after verifying the peer's Finished message and -** before processing incoming application data. -** -** For the initial handshake: If the handshake false started (see -** SSL_ENABLE_FALSE_START), then application data may already have been sent -** before the handshake callback is called. If we did not false start then the -** callback will get called before any application data is sent. -*/ -typedef void(PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd, - void *client_data); -SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd, - SSLHandshakeCallback cb, void *client_data); - -/* Applications that wish to enable TLS false start must set this callback -** function. NSS will invoke the functon to determine if a particular -** connection should use false start or not. SECSuccess indicates that the -** callback completed successfully, and if so *canFalseStart indicates if false -** start can be used. If the callback does not return SECSuccess then the -** handshake will be canceled. NSS's recommended criteria can be evaluated by -** calling SSL_RecommendedCanFalseStart. -** -** If no false start callback is registered then false start will never be -** done, even if the SSL_ENABLE_FALSE_START option is enabled. -**/ -typedef SECStatus(PR_CALLBACK *SSLCanFalseStartCallback)( - PRFileDesc *fd, void *arg, PRBool *canFalseStart); - -SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback( - PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg); - -/* This function sets *canFalseStart according to the recommended criteria for -** false start. These criteria may change from release to release and may depend -** on which handshake features have been negotiated and/or properties of the -** certifciates/keys used on the connection. -*/ -SSL_IMPORT SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd, - PRBool *canFalseStart); - -/* -** For the server, request a new handshake. For the client, begin a new -** handshake. If flushCache is non-zero, the SSL3 cache entry will be -** flushed first, ensuring that a full SSL handshake will be done. -** If flushCache is zero, and an SSL connection is established, it will -** do the much faster session restart handshake. This will change the -** session keys without doing another private key operation. -*/ -SSL_IMPORT SECStatus SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache); - -/* -** Same as above, but with an I/O timeout. - */ -SSL_IMPORT SECStatus SSL_ReHandshakeWithTimeout(PRFileDesc *fd, - PRBool flushCache, - PRIntervalTime timeout); - -/* Returns a SECItem containing the certificate_types field of the -** CertificateRequest message. Each byte of the data is a TLS -** ClientCertificateType value, and they are ordered from most preferred to -** least. This function should only be called from the -** SSL_GetClientAuthDataHook callback, and will return NULL if called at any -** other time. The returned value is valid only until the callback returns, and -** should not be freed. -*/ -SSL_IMPORT const SECItem * -SSL_GetRequestedClientCertificateTypes(PRFileDesc *fd); - -#ifdef SSL_DEPRECATED_FUNCTION -/* deprecated! -** For the server, request a new handshake. For the client, begin a new -** handshake. Flushes SSL3 session cache entry first, ensuring that a -** full handshake will be done. -** This call is equivalent to SSL_ReHandshake(fd, PR_TRUE) -*/ -SSL_IMPORT SECStatus SSL_RedoHandshake(PRFileDesc *fd); -#endif - -/* - * Allow the application to pass a URL or hostname into the SSL library. - */ -SSL_IMPORT SECStatus SSL_SetURL(PRFileDesc *fd, const char *url); - -/* - * Allow an application to define a set of trust anchors for peer - * cert validation. - */ -SSL_IMPORT SECStatus SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *list); - -/* -** Return the number of bytes that SSL has waiting in internal buffers. -** Return 0 if security is not enabled. -*/ -SSL_IMPORT int SSL_DataPending(PRFileDesc *fd); - -/* -** Invalidate the SSL session associated with fd. -*/ -SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd); - -/* -** Cache the SSL session associated with fd, if it has not already been cached. -*/ -SSL_IMPORT SECStatus SSL_CacheSession(PRFileDesc *fd); - -/* -** Cache the SSL session associated with fd, if it has not already been cached. -** This function may only be called when processing within a callback assigned -** via SSL_HandshakeCallback -*/ -SSL_IMPORT SECStatus SSL_CacheSessionUnlocked(PRFileDesc *fd); - -/* -** Return a SECItem containing the SSL session ID associated with the fd. -*/ -SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd); - -/* -** Clear out the client's SSL session cache, not the server's session cache. -*/ -SSL_IMPORT void SSL_ClearSessionCache(void); - -/* -** Close the server's SSL session cache. -*/ -SSL_IMPORT SECStatus SSL_ShutdownServerSessionIDCache(void); - -/* -** Set peer information so we can correctly look up SSL session later. -** You only have to do this if you're tunneling through a proxy. -*/ -SSL_IMPORT SECStatus SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID); - -/* -** Reveal the security information for the peer. -*/ -SSL_IMPORT CERTCertificate *SSL_RevealCert(PRFileDesc *socket); -SSL_IMPORT void *SSL_RevealPinArg(PRFileDesc *socket); -SSL_IMPORT char *SSL_RevealURL(PRFileDesc *socket); - -/* This callback may be passed to the SSL library via a call to - * SSL_GetClientAuthDataHook() for each SSL client socket. - * It will be invoked when SSL needs to know what certificate and private key - * (if any) to use to respond to a request for client authentication. - * If arg is non-NULL, it is a pointer to a NULL-terminated string containing - * the nickname of the cert/key pair to use. - * If arg is NULL, this function will search the cert and key databases for - * a suitable match and send it if one is found. - */ -SSL_IMPORT SECStatus -NSS_GetClientAuthData(void *arg, - PRFileDesc *socket, - struct CERTDistNamesStr *caNames, - struct CERTCertificateStr **pRetCert, - struct SECKEYPrivateKeyStr **pRetKey); - -/* -** Configure DTLS-SRTP (RFC 5764) cipher suite preferences. -** Input is a list of ciphers in descending preference order and a length -** of the list. As a side effect, this causes the use_srtp extension to be -** negotiated. -** -** Invalid or unimplemented cipher suites in |ciphers| are ignored. If at -** least one cipher suite in |ciphers| is implemented, returns SECSuccess. -** Otherwise returns SECFailure. -*/ -SSL_IMPORT SECStatus SSL_SetSRTPCiphers(PRFileDesc *fd, - const PRUint16 *ciphers, - unsigned int numCiphers); - -/* -** Get the selected DTLS-SRTP cipher suite (if any). -** To be called after the handshake completes. -** Returns SECFailure if not negotiated. -*/ -SSL_IMPORT SECStatus SSL_GetSRTPCipher(PRFileDesc *fd, - PRUint16 *cipher); - -/* - * Look to see if any of the signers in the cert chain for "cert" are found - * in the list of caNames. - * Returns SECSuccess if so, SECFailure if not. - * Used by NSS_GetClientAuthData. May be used by other callback functions. - */ -SSL_IMPORT SECStatus NSS_CmpCertChainWCANames(CERTCertificate *cert, - CERTDistNames *caNames); - -/* - * Returns key exchange type of the keys in an SSL server certificate. - */ -SSL_IMPORT SSLKEAType NSS_FindCertKEAType(CERTCertificate *cert); - -/* Set cipher policies to a predefined Domestic (U.S.A.) policy. - * This essentially allows all supported ciphers. - */ -SSL_IMPORT SECStatus NSS_SetDomesticPolicy(void); - -/* Set cipher policies to a predefined Policy that is exportable from the USA - * according to present U.S. policies as we understand them. - * It is the same as NSS_SetDomesticPolicy now. - */ -SSL_IMPORT SECStatus NSS_SetExportPolicy(void); - -/* Set cipher policies to a predefined Policy that is exportable from the USA - * according to present U.S. policies as we understand them, and that the - * nation of France will permit to be imported into their country. - * It is the same as NSS_SetDomesticPolicy now. - */ -SSL_IMPORT SECStatus NSS_SetFrancePolicy(void); - -SSL_IMPORT SSL3Statistics *SSL_GetStatistics(void); - -/* Report more information than SSL_SecurityStatus. - * Caller supplies the info struct. This function fills it in. Caller should - * pass sizeof(SSLChannelInfo) as the |len| argument. - * - * The information here will be zeroed prior to details being confirmed. The - * details are confirmed either when a Finished message is received, or - for a - * client - when the second flight of messages have been sent. This function - * therefore produces unreliable results prior to receiving the - * SSLHandshakeCallback or the SSLCanFalseStartCallback. - */ -SSL_IMPORT SECStatus SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, - PRUintn len); -/* Get preliminary information about a channel. - * Caller supplies the info struct. This function fills it in. Caller should - * pass sizeof(SSLPreliminaryChannelInfo) as the |len| argument. - * - * this function is available to SSLAuthCertificate, SSLGetClientAuthData, - * SSLSNISocketConfig, and other callbacks that might be called during the - * processing of the first flight of client of server handshake messages. - * Values are marked as being unavailable when renegotiation is initiated. - */ -SSL_IMPORT SECStatus -SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, - SSLPreliminaryChannelInfo *info, - PRUintn len); -/* Get information about cipher suite with id of |cipherSuite|. - * Caller supplies the info struct. This function fills it in. Caller should - * pass sizeof(SSLCipherSuiteInfo) as the |len| argument. - */ -SSL_IMPORT SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite, - SSLCipherSuiteInfo *info, PRUintn len); - -/* Returnes negotiated through SNI host info. */ -SSL_IMPORT SECItem *SSL_GetNegotiatedHostInfo(PRFileDesc *fd); - -/* Export keying material according to RFC 5705. -** fd must correspond to a TLS 1.0 or higher socket and out must -** already be allocated. If hasContext is false, it uses the no-context -** construction from the RFC and ignores the context and contextLen -** arguments. -*/ -SSL_IMPORT SECStatus SSL_ExportKeyingMaterial(PRFileDesc *fd, - const char *label, - unsigned int labelLen, - PRBool hasContext, - const unsigned char *context, - unsigned int contextLen, - unsigned char *out, - unsigned int outLen); - -/* -** Return a new reference to the certificate that was most recently sent -** to the peer on this SSL/TLS connection, or NULL if none has been sent. -*/ -SSL_IMPORT CERTCertificate *SSL_LocalCertificate(PRFileDesc *fd); - -/* Test an SSL configuration to see if SSL_BYPASS_PKCS11 can be turned on. -** Check the key exchange algorithm for each cipher in the list to see if -** a master secret key can be extracted after being derived with the mechanism -** required by the protocolmask argument. If the KEA will use keys from the -** specified cert make sure the extract operation is attempted from the slot -** where the private key resides. -** If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and -** SECSuccess is returned. In all other cases but one (*pcanbypass) is -** set to FALSE and SECFailure is returned. -** In that last case Derive() has been called successfully but the MS is null, -** CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the -** arguments were all valid but the slot cannot be bypassed. -** -** Note: A TRUE return code from CanBypass means "Your configuration will perform -** NO WORSE with the bypass enabled than without"; it does NOT mean that every -** cipher suite listed will work properly with the selected protocols. -** -** Caveat: If export cipher suites are included in the argument list Canbypass -** will return FALSE. -**/ - -/* protocol mask bits */ -#define SSL_CBP_SSL3 0x0001 /* test SSL v3 mechanisms */ -#define SSL_CBP_TLS1_0 0x0002 /* test TLS v1.0 mechanisms */ - -SSL_IMPORT SECStatus SSL_CanBypass(CERTCertificate *cert, - SECKEYPrivateKey *privKey, - PRUint32 protocolmask, - PRUint16 *ciphers, int nciphers, - PRBool *pcanbypass, void *pwArg); - -/* -** Did the handshake with the peer negotiate the given extension? -** Output parameter valid only if function returns SECSuccess -*/ -SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc *socket, - SSLExtensionType extId, - PRBool *yes); - -SSL_IMPORT SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd, - PRBool *last_handshake_resumed); - -/* See SSL_SetClientChannelIDCallback for usage. If the callback returns - * SECWouldBlock then SSL_RestartHandshakeAfterChannelIDReq should be called in - * the future to restart the handshake. On SECSuccess, the callback must have - * written a P-256, EC key pair to |*out_public_key| and |*out_private_key|. */ -typedef SECStatus(PR_CALLBACK *SSLClientChannelIDCallback)( - void *arg, - PRFileDesc *fd, - SECKEYPublicKey **out_public_key, - SECKEYPrivateKey **out_private_key); - -/* SSL_RestartHandshakeAfterChannelIDReq attempts to restart the handshake - * after a ChannelID callback returned SECWouldBlock. - * - * This function takes ownership of |channelIDPub| and |channelID|. */ -SSL_IMPORT SECStatus SSL_RestartHandshakeAfterChannelIDReq( - PRFileDesc *fd, - SECKEYPublicKey *channelIDPub, - SECKEYPrivateKey *channelID); - -/* SSL_SetClientChannelIDCallback sets a callback function that will be called - * once the server's ServerHello has been processed. This is only applicable to - * a client socket and setting this callback causes the TLS Channel ID - * extension to be advertised. */ -SSL_IMPORT SECStatus SSL_SetClientChannelIDCallback( - PRFileDesc *fd, - SSLClientChannelIDCallback callback, - void *arg); - -/* -** How long should we wait before retransmitting the next flight of -** the DTLS handshake? Returns SECFailure if not DTLS or not in a -** handshake. -*/ -SSL_IMPORT SECStatus DTLS_GetHandshakeTimeout(PRFileDesc *socket, - PRIntervalTime *timeout); - -/* - * Return a boolean that indicates whether the underlying library - * will perform as the caller expects. - * - * The only argument is a string, which should be the version - * identifier of the NSS library. That string will be compared - * against a string that represents the actual build version of - * the SSL library. - */ -extern PRBool NSSSSL_VersionCheck(const char *importedVersion); - -/* - * Returns a const string of the SSL library version. - */ -extern const char *NSSSSL_GetVersion(void); - -/* Restart an SSL connection that was paused to do asynchronous certificate - * chain validation (when the auth certificate hook or bad cert handler - * returned SECWouldBlock). - * - * This function only works for non-blocking sockets; Do not use it for - * blocking sockets. Currently, this function works only for the client role of - * a connection; it does not work for the server role. - * - * The application must call SSL_AuthCertificateComplete with 0 as the value of - * the error parameter after it has successfully validated the peer's - * certificate, in order to continue the SSL handshake. - * - * The application may call SSL_AuthCertificateComplete with a non-zero value - * for error (e.g. SEC_ERROR_REVOKED_CERTIFICATE) when certificate validation - * fails, before it closes the connection. If the application does so, an - * alert corresponding to the error (e.g. certificate_revoked) will be sent to - * the peer. See the source code of the internal function - * ssl3_SendAlertForCertError for the current mapping of error to alert. This - * mapping may change in future versions of libssl. - * - * This function will not complete the entire handshake. The application must - * call SSL_ForceHandshake, PR_Recv, PR_Send, etc. after calling this function - * to force the handshake to complete. - * - * On the first handshake of a connection, libssl will wait for the peer's - * certificate to be authenticated before calling the handshake callback, - * sending a client certificate, sending any application data, or returning - * any application data to the application. On subsequent (renegotiation) - * handshakes, libssl will block the handshake unconditionally while the - * certificate is being validated. - * - * libssl may send and receive handshake messages while waiting for the - * application to call SSL_AuthCertificateComplete, and it may call other - * callbacks (e.g, the client auth data hook) before - * SSL_AuthCertificateComplete has been called. - * - * An application that uses this asynchronous mechanism will usually have lower - * handshake latency if it has to do public key operations on the certificate - * chain and/or CRL/OCSP/cert fetching during the authentication, especially if - * it does so in parallel on another thread. However, if the application can - * authenticate the peer's certificate quickly then it may be more efficient - * to use the synchronous mechanism (i.e. returning SECFailure/SECSuccess - * instead of SECWouldBlock from the authenticate certificate hook). - * - * Be careful about converting an application from synchronous cert validation - * to asynchronous certificate validation. A naive conversion is likely to - * result in deadlocks; e.g. the application will wait in PR_Poll for network - * I/O on the connection while all network I/O on the connection is blocked - * waiting for this function to be called. - * - * Returns SECFailure on failure, SECSuccess on success. Never returns - * SECWouldBlock. Note that SSL_AuthCertificateComplete will (usually) return - * SECSuccess; do not interpret the return value of SSL_AuthCertificateComplete - * as an indicator of whether it is OK to continue using the connection. For - * example, SSL_AuthCertificateComplete(fd, SEC_ERROR_REVOKED_CERTIFICATE) will - * return SECSuccess (normally), but that does not mean that the application - * should continue using the connection. If the application passes a non-zero - * value for second argument (error), or if SSL_AuthCertificateComplete returns - * anything other than SECSuccess, then the application should close the - * connection. - */ -SSL_IMPORT SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd, - PRErrorCode error); -SEC_END_PROTOS - -#endif /* __ssl_h_ */
diff --git a/net/third_party/nss/ssl/ssl.rc b/net/third_party/nss/ssl/ssl.rc deleted file mode 100644 index 809a07e..0000000 --- a/net/third_party/nss/ssl/ssl.rc +++ /dev/null
@@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nss.h" -#include <winver.h> - -#define MY_LIBNAME "ssl" -#define MY_FILEDESCRIPTION "NSS SSL Library" - -#define STRINGIZE(x) #x -#define STRINGIZE2(x) STRINGIZE(x) -#define NSS_VMAJOR_STR STRINGIZE2(NSS_VMAJOR) - -#ifdef _DEBUG -#define MY_DEBUG_STR " (debug)" -#define MY_FILEFLAGS_1 VS_FF_DEBUG -#else -#define MY_DEBUG_STR "" -#define MY_FILEFLAGS_1 0x0L -#endif -#if NSS_BETA -#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE -#else -#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 -#endif - -#ifdef WINNT -#define MY_FILEOS VOS_NT_WINDOWS32 -#else -#define MY_FILEOS VOS__WINDOWS32 -#endif - -#define MY_INTERNAL_NAME MY_LIBNAME NSS_VMAJOR_STR - -///////////////////////////////////////////////////////////////////////////// -// -// Version-information resource -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION NSS_VMAJOR,NSS_VMINOR,NSS_VPATCH,NSS_VBUILD - PRODUCTVERSION NSS_VMAJOR,NSS_VMINOR,NSS_VPATCH,NSS_VBUILD - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK - FILEFLAGS MY_FILEFLAGS_2 - FILEOS MY_FILEOS - FILETYPE VFT_DLL - FILESUBTYPE 0x0L // not used - -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904B0" // Lang=US English, CharSet=Unicode - BEGIN - VALUE "CompanyName", "Mozilla Foundation\0" - VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" - VALUE "FileVersion", NSS_VERSION "\0" - VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" - VALUE "ProductName", "Network Security Services\0" - VALUE "ProductVersion", NSS_VERSION "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c deleted file mode 100644 index b6f4987b..0000000 --- a/net/third_party/nss/ssl/ssl3con.c +++ /dev/null
@@ -1,14146 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * SSL3 Protocol - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */ - -#include "cert.h" -#include "ssl.h" -#include "cryptohi.h" /* for DSAU_ stuff */ -#include "keyhi.h" -#include "secder.h" -#include "secitem.h" -#include "sechash.h" - -#include "sslimpl.h" -#include "sslproto.h" -#include "sslerr.h" -#include "prtime.h" -#include "prinrval.h" -#include "prerror.h" -#include "pratom.h" -#include "prthread.h" -#include "nss.h" -#include "nssoptions.h" - -#include "pk11func.h" -#include "secmod.h" -#ifndef NO_PKCS11_BYPASS -#include "blapi.h" -#endif - -#include <stdio.h> -#ifdef NSS_SSL_ENABLE_ZLIB -#include "zlib.h" -#endif - -#ifndef PK11_SETATTRS -#define PK11_SETATTRS(x, id, v, l) \ - (x)->type = (id); \ - (x)->pValue = (v); \ - (x)->ulValueLen = (l); -#endif - -static SECStatus ssl3_AuthCertificate(sslSocket *ss); -static void ssl3_CleanupPeerCerts(sslSocket *ss); -static void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid); -static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, - PK11SlotInfo *serverKeySlot); -static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); -static SECStatus ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss); -static SECStatus ssl3_HandshakeFailure(sslSocket *ss); -static SECStatus ssl3_InitState(sslSocket *ss); - -static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); -static SECStatus ssl3_SendNextProto(sslSocket *ss); -static SECStatus ssl3_SendChannelIDEncryptedExtensions(sslSocket *ss); -static SECStatus ssl3_SendFinished(sslSocket *ss, PRInt32 flags); -static SECStatus ssl3_SendServerHelloDone(sslSocket *ss); -static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss); -static SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss, - const unsigned char *b, - unsigned int l); -static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, - SSL3Opaque *b, - PRUint32 length, - SSL3Hashes *hashesPtr); -static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); - -static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, - int maxOutputLen, const unsigned char *input, - int inputLen); -#ifndef NO_PKCS11_BYPASS -static SECStatus ssl3_AESGCMBypass(ssl3KeyMaterial *keys, PRBool doDecrypt, - unsigned char *out, int *outlen, int maxout, - const unsigned char *in, int inlen, - const unsigned char *additionalData, - int additionalDataLen); -#endif - -#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */ -#define MIN_SEND_BUF_LENGTH 4000 - -/* This list of SSL3 cipher suites is sorted in descending order of - * precedence (desirability). It only includes cipher suites we implement. - * This table is modified by SSL3_SetPolicy(). The ordering of cipher suites - * in this table must match the ordering in SSL_ImplementedCiphers (sslenum.c) - * - * Important: See bug 946147 before enabling, reordering, or adding any cipher - * suites to this list. - */ -/* clang-format off */ -static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { - /* cipher_suite policy enabled isPresent */ - -#ifndef NSS_DISABLE_ECC - { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around - * bug 946147. - */ - { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, -#endif /* NSS_DISABLE_ECC */ - - { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,SSL_ALLOWED,PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - -#ifndef NSS_DISABLE_ECC - { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, -#endif /* NSS_DISABLE_ECC */ - - /* RSA */ - { TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_WITH_SEED_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_RC4_128_MD5, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - - /* 56-bit DES "domestic" cipher suites */ - { TLS_DHE_RSA_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_DSS_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - - /* export ciphersuites with 1024-bit public key exchange keys */ - { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - - /* export ciphersuites with 512-bit public key exchange keys */ - { TLS_RSA_EXPORT_WITH_RC4_40_MD5, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - - /* ciphersuites with no encryption */ -#ifndef NSS_DISABLE_ECC - { TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, -#endif /* NSS_DISABLE_ECC */ - { TLS_RSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_WITH_NULL_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_RSA_WITH_NULL_MD5, SSL_ALLOWED, PR_FALSE, PR_FALSE}, -}; -/* clang-format on */ - -static const SSLSignatureAndHashAlg defaultSignatureAlgorithms[] = { - { ssl_hash_sha256, ssl_sign_rsa }, - { ssl_hash_sha384, ssl_sign_rsa }, - { ssl_hash_sha512, ssl_sign_rsa }, - { ssl_hash_sha1, ssl_sign_rsa }, -#ifndef NSS_DISABLE_ECC - { ssl_hash_sha256, ssl_sign_ecdsa }, - { ssl_hash_sha384, ssl_sign_ecdsa }, - { ssl_hash_sha512, ssl_sign_ecdsa }, - { ssl_hash_sha1, ssl_sign_ecdsa }, -#endif - { ssl_hash_sha256, ssl_sign_dsa }, - { ssl_hash_sha1, ssl_sign_dsa } -}; -PR_STATIC_ASSERT(PR_ARRAY_SIZE(defaultSignatureAlgorithms) <= - MAX_SIGNATURE_ALGORITHMS); - -/* Verify that SSL_ImplementedCiphers and cipherSuites are in consistent order. - */ -#ifdef DEBUG -void -ssl3_CheckCipherSuiteOrderConsistency() -{ - unsigned int i; - - /* Note that SSL_ImplementedCiphers has more elements than cipherSuites - * because it SSL_ImplementedCiphers includes SSL 2.0 cipher suites. - */ - PORT_Assert(SSL_NumImplementedCiphers >= PR_ARRAY_SIZE(cipherSuites)); - - for (i = 0; i < PR_ARRAY_SIZE(cipherSuites); ++i) { - PORT_Assert(SSL_ImplementedCiphers[i] == cipherSuites[i].cipher_suite); - } -} -#endif - -/* This list of SSL3 compression methods is sorted in descending order of - * precedence (desirability). It only includes compression methods we - * implement. - */ -static const /*SSLCompressionMethod*/ PRUint8 compressions[] = { -#ifdef NSS_SSL_ENABLE_ZLIB - ssl_compression_deflate, -#endif - ssl_compression_null -}; - -static const int compressionMethodsCount = - sizeof(compressions) / sizeof(compressions[0]); - -/* compressionEnabled returns true iff the compression algorithm is enabled - * for the given SSL socket. */ -static PRBool -compressionEnabled(sslSocket *ss, SSLCompressionMethod compression) -{ - switch (compression) { - case ssl_compression_null: - return PR_TRUE; /* Always enabled */ -#ifdef NSS_SSL_ENABLE_ZLIB - case ssl_compression_deflate: - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return ss->opt.enableDeflate; - } - return PR_FALSE; -#endif - default: - return PR_FALSE; - } -} - -static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = { - ct_RSA_sign, -#ifndef NSS_DISABLE_ECC - ct_ECDSA_sign, -#endif /* NSS_DISABLE_ECC */ - ct_DSS_sign, -}; - -#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */ - -/* This global item is used only in servers. It is is initialized by -** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest(). -*/ -CERTDistNames *ssl3_server_ca_list = NULL; -static SSL3Statistics ssl3stats; - -/* indexed by SSL3BulkCipher */ -/* clang-format off */ -static const ssl3BulkCipherDef bulk_cipher_defs[] = { - /* |--------- Lengths --------| */ - /* cipher calg k s type i b t n o */ - /* e e v l a o i */ - /* y c | o g n d */ - /* | r | c | c | */ - /* | e | k | e | */ - /* | t | | | | | */ - {cipher_null, calg_null, 0, 0, type_stream, 0, 0, 0, 0, SEC_OID_NULL_CIPHER}, - {cipher_rc4, calg_rc4, 16,16, type_stream, 0, 0, 0, 0, SEC_OID_RC4}, - {cipher_rc4_40, calg_rc4, 16, 5, type_stream, 0, 0, 0, 0, SEC_OID_RC4_40}, - {cipher_rc4_56, calg_rc4, 16, 7, type_stream, 0, 0, 0, 0, SEC_OID_RC4_56}, - {cipher_rc2, calg_rc2, 16,16, type_block, 8, 8, 0, 0, SEC_OID_RC2_CBC}, - {cipher_rc2_40, calg_rc2, 16, 5, type_block, 8, 8, 0, 0, SEC_OID_RC2_40_CBC}, - {cipher_des, calg_des, 8, 8, type_block, 8, 8, 0, 0, SEC_OID_DES_CBC}, - {cipher_3des, calg_3des, 24,24, type_block, 8, 8, 0, 0, SEC_OID_DES_EDE3_CBC}, - {cipher_des40, calg_des, 8, 5, type_block, 8, 8, 0, 0, SEC_OID_DES_40_CBC}, - {cipher_idea, calg_idea, 16,16, type_block, 8, 8, 0, 0, SEC_OID_IDEA_CBC}, - {cipher_aes_128, calg_aes, 16,16, type_block, 16,16, 0, 0, SEC_OID_AES_128_CBC}, - {cipher_aes_256, calg_aes, 32,32, type_block, 16,16, 0, 0, SEC_OID_AES_256_CBC}, - {cipher_camellia_128, calg_camellia, 16,16, type_block, 16,16, 0, 0, SEC_OID_CAMELLIA_128_CBC}, - {cipher_camellia_256, calg_camellia, 32,32, type_block, 16,16, 0, 0, SEC_OID_CAMELLIA_256_CBC}, - {cipher_seed, calg_seed, 16,16, type_block, 16,16, 0, 0, SEC_OID_SEED_CBC}, - {cipher_aes_128_gcm, calg_aes_gcm, 16,16, type_aead, 4, 0,16, 8, SEC_OID_AES_128_GCM}, - {cipher_chacha20, calg_chacha20, 32,32, type_aead, 12, 0,16, 0, SEC_OID_CHACHA20_POLY1305}, - {cipher_missing, calg_null, 0, 0, type_stream, 0, 0, 0, 0, 0}, -}; - -static const ssl3KEADef kea_defs[] = -{ /* indexed by SSL3KeyExchangeAlgorithm */ - /* kea exchKeyType signKeyType is_limited limit tls_keygen ephemeral oid */ - {kea_null, kt_null, ssl_sign_null, PR_FALSE, 0, PR_FALSE, PR_FALSE, 0}, - {kea_rsa, kt_rsa, ssl_sign_rsa, PR_FALSE, 0, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA}, - {kea_rsa_export, kt_rsa, ssl_sign_rsa, PR_TRUE, 512, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT}, - {kea_rsa_export_1024,kt_rsa, ssl_sign_rsa, PR_TRUE, 1024, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT}, - {kea_dh_dss, kt_dh, ssl_sign_dsa, PR_FALSE, 0, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_DSS}, - {kea_dh_dss_export, kt_dh, ssl_sign_dsa, PR_TRUE, 512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_DSS_EXPORT}, - {kea_dh_rsa, kt_dh, ssl_sign_rsa, PR_FALSE, 0, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA}, - {kea_dh_rsa_export, kt_dh, ssl_sign_rsa, PR_TRUE, 512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA_EXPORT}, - {kea_dhe_dss, kt_dh, ssl_sign_dsa, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_DHE_DSS}, - {kea_dhe_dss_export, kt_dh, ssl_sign_dsa, PR_TRUE, 512, PR_FALSE, PR_TRUE, SEC_OID_TLS_DHE_DSS_EXPORT}, - {kea_dhe_rsa, kt_dh, ssl_sign_rsa, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_DHE_RSA}, - {kea_dhe_rsa_export, kt_dh, ssl_sign_rsa, PR_TRUE, 512, PR_FALSE, PR_TRUE, SEC_OID_TLS_DHE_RSA_EXPORT}, - {kea_dh_anon, kt_dh, ssl_sign_null, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_DH_ANON}, - {kea_dh_anon_export, kt_dh, ssl_sign_null, PR_TRUE, 512, PR_FALSE, PR_TRUE, SEC_OID_TLS_DH_ANON_EXPORT}, - {kea_rsa_fips, kt_rsa, ssl_sign_rsa, PR_FALSE, 0, PR_TRUE, PR_FALSE, SEC_OID_TLS_RSA}, -#ifndef NSS_DISABLE_ECC - {kea_ecdh_ecdsa, kt_ecdh, ssl_sign_ecdsa, PR_FALSE, 0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA}, - {kea_ecdhe_ecdsa, kt_ecdh, ssl_sign_ecdsa, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDHE_ECDSA}, - {kea_ecdh_rsa, kt_ecdh, ssl_sign_rsa, PR_FALSE, 0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_RSA}, - {kea_ecdhe_rsa, kt_ecdh, ssl_sign_rsa, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDHE_RSA}, - {kea_ecdh_anon, kt_ecdh, ssl_sign_null, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDH_ANON}, -#endif /* NSS_DISABLE_ECC */ -}; - -/* must use ssl_LookupCipherSuiteDef to access */ -static const ssl3CipherSuiteDef cipher_suite_defs[] = -{ -/* cipher_suite bulk_cipher_alg mac_alg key_exchange_alg */ - - {TLS_NULL_WITH_NULL_NULL, cipher_null, mac_null, kea_null}, - {TLS_RSA_WITH_NULL_MD5, cipher_null, mac_md5, kea_rsa}, - {TLS_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_rsa}, - {TLS_RSA_WITH_NULL_SHA256, cipher_null, hmac_sha256, kea_rsa}, - {TLS_RSA_EXPORT_WITH_RC4_40_MD5,cipher_rc4_40, mac_md5, kea_rsa_export}, - {TLS_RSA_WITH_RC4_128_MD5, cipher_rc4, mac_md5, kea_rsa}, - {TLS_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_rsa}, - {TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, - cipher_rc2_40, mac_md5, kea_rsa_export}, -#if 0 /* not implemented */ - {TLS_RSA_WITH_IDEA_CBC_SHA, cipher_idea, mac_sha, kea_rsa}, - {TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, - cipher_des40, mac_sha, kea_rsa_export}, -#endif - {TLS_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa}, - {TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa}, - {TLS_DHE_DSS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_dss}, - {TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - cipher_3des, mac_sha, kea_dhe_dss}, - {TLS_DHE_DSS_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_dhe_dss}, -#if 0 /* not implemented */ - {TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, - cipher_des40, mac_sha, kea_dh_dss_export}, - {TLS_DH_DSS_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_dss}, - {TLS_DH_DSS_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_dss}, - {TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, - cipher_des40, mac_sha, kea_dh_rsa_export}, - {TLS_DH_RSA_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_rsa}, - {TLS_DH_RSA_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_rsa}, - {TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, - cipher_des40, mac_sha, kea_dh_dss_export}, - {TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, - cipher_des40, mac_sha, kea_dh_rsa_export}, -#endif - {TLS_DHE_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_rsa}, - {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - cipher_3des, mac_sha, kea_dhe_rsa}, -#if 0 - {SSL_DH_ANON_EXPORT_RC4_40_MD5, cipher_rc4_40, mac_md5, kea_dh_anon_export}, - {TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, - cipher_des40, mac_sha, kea_dh_anon_export}, - {TLS_DH_anon_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_anon}, - {TLS_DH_anon_WITH_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_anon}, -#endif - - -/* New TLS cipher suites */ - {TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_rsa}, - {TLS_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_rsa}, - {TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_dss}, - {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_rsa}, - {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_rsa}, - {TLS_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_rsa}, - {TLS_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_rsa}, - {TLS_DHE_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_dss}, - {TLS_DHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_rsa}, - {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_rsa}, -#if 0 - {TLS_DH_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_dss}, - {TLS_DH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_rsa}, - {TLS_DH_anon_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_anon}, - {TLS_DH_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_dss}, - {TLS_DH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_rsa}, - {TLS_DH_anon_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_anon}, -#endif - - {TLS_RSA_WITH_SEED_CBC_SHA, cipher_seed, mac_sha, kea_rsa}, - - {TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, mac_sha, kea_rsa}, - {TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, - cipher_camellia_128, mac_sha, kea_dhe_dss}, - {TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, - cipher_camellia_128, mac_sha, kea_dhe_rsa}, - {TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, mac_sha, kea_rsa}, - {TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, - cipher_camellia_256, mac_sha, kea_dhe_dss}, - {TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, - cipher_camellia_256, mac_sha, kea_dhe_rsa}, - - {TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, - cipher_des, mac_sha,kea_rsa_export_1024}, - {TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - cipher_rc4_56, mac_sha,kea_rsa_export_1024}, - - {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips}, - {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa_fips}, - - {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa}, - {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa}, - {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa}, - {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa}, - - {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss}, - {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss}, - {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss}, - - {TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_dhe_rsa}, - {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_rsa}, - {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_ecdsa}, - -#ifndef NSS_DISABLE_ECC - {TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_ecdsa}, - {TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_ecdsa}, - {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa}, - {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa}, - {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa}, - - {TLS_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_ecdsa}, - {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_ecdsa}, - {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_ecdsa}, - {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_ecdsa}, - - {TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_rsa}, - {TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_rsa}, - {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_rsa}, - {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_rsa}, - {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_rsa}, - - {TLS_ECDHE_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_rsa}, - -#if 0 - {TLS_ECDH_anon_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_anon}, - {TLS_ECDH_anon_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_anon}, - {TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_anon}, - {TLS_ECDH_anon_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_anon}, - {TLS_ECDH_anon_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_anon}, -#endif -#endif /* NSS_DISABLE_ECC */ -}; -/* clang-format on */ - -static const CK_MECHANISM_TYPE kea_alg_defs[] = { - 0x80000000L, - CKM_RSA_PKCS, - CKM_DH_PKCS_DERIVE, - CKM_KEA_KEY_DERIVE, - CKM_ECDH1_DERIVE -}; - -typedef struct SSLCipher2MechStr { - SSLCipherAlgorithm calg; - CK_MECHANISM_TYPE cmech; -} SSLCipher2Mech; - -/* indexed by type SSLCipherAlgorithm */ -static const SSLCipher2Mech alg2Mech[] = { - /* calg, cmech */ - { calg_null, (CK_MECHANISM_TYPE)0x80000000L }, - { calg_rc4, CKM_RC4 }, - { calg_rc2, CKM_RC2_CBC }, - { calg_des, CKM_DES_CBC }, - { calg_3des, CKM_DES3_CBC }, - { calg_idea, CKM_IDEA_CBC }, - { calg_fortezza, CKM_SKIPJACK_CBC64 }, - { calg_aes, CKM_AES_CBC }, - { calg_camellia, CKM_CAMELLIA_CBC }, - { calg_seed, CKM_SEED_CBC }, - { calg_aes_gcm, CKM_AES_GCM }, - { calg_chacha20, CKM_NSS_CHACHA20_POLY1305 }, - /* { calg_init , (CK_MECHANISM_TYPE)0x7fffffffL } */ -}; - -#define mmech_invalid (CK_MECHANISM_TYPE)0x80000000L -#define mmech_md5 CKM_SSL3_MD5_MAC -#define mmech_sha CKM_SSL3_SHA1_MAC -#define mmech_md5_hmac CKM_MD5_HMAC -#define mmech_sha_hmac CKM_SHA_1_HMAC -#define mmech_sha256_hmac CKM_SHA256_HMAC - -/* clang-format off */ -static const ssl3MACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */ - /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */ - /* mac mmech pad_size mac_size */ - { mac_null, mmech_invalid, 0, 0 , 0}, - { mac_md5, mmech_md5, 48, MD5_LENGTH, SEC_OID_HMAC_MD5 }, - { mac_sha, mmech_sha, 40, SHA1_LENGTH, SEC_OID_HMAC_SHA1}, - {hmac_md5, mmech_md5_hmac, 0, MD5_LENGTH, SEC_OID_HMAC_MD5}, - {hmac_sha, mmech_sha_hmac, 0, SHA1_LENGTH, SEC_OID_HMAC_SHA1}, - {hmac_sha256, mmech_sha256_hmac, 0, SHA256_LENGTH, SEC_OID_HMAC_SHA256}, - { mac_aead, mmech_invalid, 0, 0, 0 }, -}; -/* clang-format on */ - -/* indexed by SSL3BulkCipher */ -const char *const ssl3_cipherName[] = { - "NULL", - "RC4", - "RC4-40", - "RC4-56", - "RC2-CBC", - "RC2-CBC-40", - "DES-CBC", - "3DES-EDE-CBC", - "DES-CBC-40", - "IDEA-CBC", - "AES-128", - "AES-256", - "Camellia-128", - "Camellia-256", - "SEED-CBC", - "AES-128-GCM", - "missing" -}; - -const PRUint8 tls13_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, - 0x47, 0x52, 0x44, 0x01 }; -const PRUint8 tls12_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, - 0x47, 0x52, 0x44, 0x00 }; - -#ifndef NSS_DISABLE_ECC -/* The ECCWrappedKeyInfo structure defines how various pieces of - * information are laid out within wrappedSymmetricWrappingkey - * for ECDH key exchange. Since wrappedSymmetricWrappingkey is - * a 512-byte buffer (see sslimpl.h), the variable length field - * in ECCWrappedKeyInfo can be at most (512 - 8) = 504 bytes. - * - * XXX For now, NSS only supports named elliptic curves of size 571 bits - * or smaller. The public value will fit within 145 bytes and EC params - * will fit within 12 bytes. We'll need to revisit this when NSS - * supports arbitrary curves. - */ -#define MAX_EC_WRAPPED_KEY_BUFLEN 504 - -typedef struct ECCWrappedKeyInfoStr { - PRUint16 size; /* EC public key size in bits */ - PRUint16 encodedParamLen; /* length (in bytes) of DER encoded EC params */ - PRUint16 pubValueLen; /* length (in bytes) of EC public value */ - PRUint16 wrappedKeyLen; /* length (in bytes) of the wrapped key */ - PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */ - /* EC public-key params, the EC public value and the wrapped key */ -} ECCWrappedKeyInfo; -#endif /* NSS_DISABLE_ECC */ - -CK_MECHANISM_TYPE -ssl3_Alg2Mech(SSLCipherAlgorithm calg) -{ - PORT_Assert(alg2Mech[calg].calg == calg); - return alg2Mech[calg].cmech; -} - -#if defined(TRACE) - -static char * -ssl3_DecodeHandshakeType(int msgType) -{ - char *rv; - static char line[40]; - - switch (msgType) { - case hello_request: - rv = "hello_request (0)"; - break; - case client_hello: - rv = "client_hello (1)"; - break; - case server_hello: - rv = "server_hello (2)"; - break; - case hello_verify_request: - rv = "hello_verify_request (3)"; - break; - case encrypted_extensions: - rv = "encrypted_extensions (8)"; - break; - case certificate: - rv = "certificate (11)"; - break; - case server_key_exchange: - rv = "server_key_exchange (12)"; - break; - case certificate_request: - rv = "certificate_request (13)"; - break; - case server_hello_done: - rv = "server_hello_done (14)"; - break; - case certificate_verify: - rv = "certificate_verify (15)"; - break; - case client_key_exchange: - rv = "client_key_exchange (16)"; - break; - case finished: - rv = "finished (20)"; - break; - default: - sprintf(line, "*UNKNOWN* handshake type! (%d)", msgType); - rv = line; - } - return rv; -} - -static char * -ssl3_DecodeContentType(int msgType) -{ - char *rv; - static char line[40]; - - switch (msgType) { - case content_change_cipher_spec: - rv = "change_cipher_spec (20)"; - break; - case content_alert: - rv = "alert (21)"; - break; - case content_handshake: - rv = "handshake (22)"; - break; - case content_application_data: - rv = "application_data (23)"; - break; - default: - sprintf(line, "*UNKNOWN* record type! (%d)", msgType); - rv = line; - } - return rv; -} - -#endif - -SSL3Statistics * -SSL_GetStatistics(void) -{ - return &ssl3stats; -} - -typedef struct tooLongStr { -#if defined(IS_LITTLE_ENDIAN) - PRInt32 low; - PRInt32 high; -#else - PRInt32 high; - PRInt32 low; -#endif -} tooLong; - -void -SSL_AtomicIncrementLong(long *x) -{ - if ((sizeof *x) == sizeof(PRInt32)) { - PR_ATOMIC_INCREMENT((PRInt32 *)x); - } else { - tooLong *tl = (tooLong *)x; - if (PR_ATOMIC_INCREMENT(&tl->low) == 0) - PR_ATOMIC_INCREMENT(&tl->high); - } -} - -static PRBool -ssl3_CipherSuiteAllowedForVersionRange( - ssl3CipherSuite cipherSuite, - const SSLVersionRange *vrange) -{ - switch (cipherSuite) { - /* See RFC 4346 A.5. Export cipher suites must not be used in TLS 1.1 or - * later. This set of cipher suites is similar to, but different from, the - * set of cipher suites considered exportable by SSL_IsExportCipherSuite. - */ - case TLS_RSA_EXPORT_WITH_RC4_40_MD5: - case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5: - /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA: never implemented - * TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: never implemented - * TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: never implemented - * TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: never implemented - * TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: never implemented - * TLS_DH_anon_EXPORT_WITH_RC4_40_MD5: never implemented - * TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA: never implemented - */ - return vrange->min <= SSL_LIBRARY_VERSION_TLS_1_0; - - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: - case TLS_RSA_WITH_AES_256_CBC_SHA256: - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: - case TLS_RSA_WITH_AES_128_CBC_SHA256: - case TLS_RSA_WITH_AES_128_GCM_SHA256: - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: - case TLS_RSA_WITH_NULL_SHA256: - case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: - return vrange->max == SSL_LIBRARY_VERSION_TLS_1_2; - - case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: - case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: - case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: - return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2; - - /* RFC 4492: ECC cipher suites need TLS extensions to negotiate curves and - * point formats.*/ - case TLS_ECDH_ECDSA_WITH_NULL_SHA: - case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: - case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: - case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: - case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: - case TLS_ECDHE_ECDSA_WITH_NULL_SHA: - case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: - case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: - case TLS_ECDH_RSA_WITH_NULL_SHA: - case TLS_ECDH_RSA_WITH_RC4_128_SHA: - case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: - case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: - case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: - case TLS_ECDHE_RSA_WITH_NULL_SHA: - case TLS_ECDHE_RSA_WITH_RC4_128_SHA: - case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_0 && - vrange->min < SSL_LIBRARY_VERSION_TLS_1_3; - - default: - return vrange->min < SSL_LIBRARY_VERSION_TLS_1_3; - } -} - -/* return pointer to ssl3CipherSuiteDef for suite, or NULL */ -/* XXX This does a linear search. A binary search would be better. */ -static const ssl3CipherSuiteDef * -ssl_LookupCipherSuiteDef(ssl3CipherSuite suite) -{ - int cipher_suite_def_len = - sizeof(cipher_suite_defs) / sizeof(cipher_suite_defs[0]); - int i; - - for (i = 0; i < cipher_suite_def_len; i++) { - if (cipher_suite_defs[i].cipher_suite == suite) - return &cipher_suite_defs[i]; - } - PORT_Assert(PR_FALSE); /* We should never get here. */ - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - return NULL; -} - -/* Find the cipher configuration struct associate with suite */ -/* XXX This does a linear search. A binary search would be better. */ -static ssl3CipherSuiteCfg * -ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, ssl3CipherSuiteCfg *suites) -{ - int i; - - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - if (suites[i].cipher_suite == suite) - return &suites[i]; - } - /* return NULL and let the caller handle it. */ - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - return NULL; -} - -/* Initialize the suite->isPresent value for config_match - * Returns count of enabled ciphers supported by extant tokens, - * regardless of policy or user preference. - * If this returns zero, the user cannot do SSL v3. - */ -int -ssl3_config_match_init(sslSocket *ss) -{ - ssl3CipherSuiteCfg *suite; - const ssl3CipherSuiteDef *cipher_def; - SSLCipherAlgorithm cipher_alg; - CK_MECHANISM_TYPE cipher_mech; - SSL3KEAType exchKeyType; - int i; - int numPresent = 0; - int numEnabled = 0; - PRBool isServer; - sslServerCerts *svrAuth; - - PORT_Assert(ss); - if (!ss) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return 0; - } - if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - return 0; - } - isServer = (PRBool)(ss->sec.isServer != 0); - - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - suite = &ss->cipherSuites[i]; - if (suite->enabled) { - ++numEnabled; - /* We need the cipher defs to see if we have a token that can handle - * this cipher. It isn't part of the static definition. - */ - cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite); - if (!cipher_def) { - suite->isPresent = PR_FALSE; - continue; - } - cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg; - cipher_mech = ssl3_Alg2Mech(cipher_alg); - exchKeyType = - kea_defs[cipher_def->key_exchange_alg].exchKeyType; -#ifdef NSS_DISABLE_ECC - svrAuth = ss->serverCerts + exchKeyType; -#else - /* XXX SSLKEAType isn't really a good choice for - * indexing certificates. It doesn't work for - * (EC)DHE-* ciphers. Here we use a hack to ensure - * that the server uses an RSA cert for (EC)DHE-RSA. - */ - switch (cipher_def->key_exchange_alg) { - case kea_dhe_dss: - svrAuth = ss->serverCerts + ssl_kea_dh; - break; - case kea_ecdhe_rsa: - case kea_dhe_rsa: - svrAuth = ss->serverCerts + kt_rsa; - break; - case kea_ecdh_ecdsa: - case kea_ecdh_rsa: - /* - * XXX We ought to have different indices for - * ECDSA- and RSA-signed EC certificates so - * we could support both key exchange mechanisms - * simultaneously. For now, both of them use - * whatever is in the certificate slot for kt_ecdh - */ - case kea_dhe_dss_export: - case kea_dhe_rsa_export: - default: - svrAuth = ss->serverCerts + exchKeyType; - break; - } -#endif /* NSS_DISABLE_ECC */ - - /* Mark the suites that are backed by real tokens, certs and keys */ - suite->isPresent = (PRBool)(((exchKeyType == kt_null) || - ((!isServer || - (svrAuth->serverKeyPair && svrAuth->SERVERKEY && - svrAuth->serverCertChain)) && - PK11_TokenExists(kea_alg_defs[exchKeyType]))) && - ((cipher_alg == calg_null) || PK11_TokenExists(cipher_mech))); - if (suite->isPresent) - ++numPresent; - } - } - PORT_Assert(numPresent > 0 || numEnabled == 0); - if (numPresent <= 0) { - PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED); - } - return numPresent; -} - -/* return PR_TRUE if suite matches policy, enabled state and is applicable to - * the given version range. */ -/* It would be a REALLY BAD THING (tm) if we ever permitted the use -** of a cipher that was NOT_ALLOWED. So, if this is ever called with -** policy == SSL_NOT_ALLOWED, report no match. -*/ -/* adjust suite enabled to the availability of a token that can do the - * cipher suite. */ -static PRBool -config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled, - const SSLVersionRange *vrange, const sslSocket *ss) -{ - const ssl3CipherSuiteDef *cipher_def; - - PORT_Assert(policy != SSL_NOT_ALLOWED && enabled != PR_FALSE); - if (policy == SSL_NOT_ALLOWED || !enabled) - return PR_FALSE; - - cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite); - PORT_Assert(cipher_def != NULL); - - PORT_Assert(ss != NULL); - if (ss->sec.isServer && !ss->opt.enableServerDhe && - kea_defs[cipher_def->key_exchange_alg].exchKeyType == ssl_kea_dh) - return PR_FALSE; - - return (PRBool)(suite->enabled && - suite->isPresent && - suite->policy != SSL_NOT_ALLOWED && - suite->policy <= policy && - ssl3_CipherSuiteAllowedForVersionRange( - suite->cipher_suite, vrange)); -} - -/* return number of cipher suites that match policy, enabled state and are - * applicable for the configured protocol version range. */ -/* called from ssl3_SendClientHello and ssl3_ConstructV2CipherSpecsHack */ -static int -count_cipher_suites(sslSocket *ss, int policy, PRBool enabled) -{ - int i, count = 0; - - if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - return 0; - } - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - if (config_match(&ss->cipherSuites[i], policy, enabled, &ss->vrange, ss)) - count++; - } - if (count <= 0) { - PORT_SetError(SSL_ERROR_SSL_DISABLED); - } - return count; -} - -/* - * Null compression, mac and encryption functions - */ - -static SECStatus -Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, - const unsigned char *input, int inputLen) -{ - if (inputLen > maxOutputLen) { - *outputLen = 0; /* Match PK11_CipherOp in setting outputLen */ - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return SECFailure; - } - *outputLen = inputLen; - if (input != output) - PORT_Memcpy(output, input, inputLen); - return SECSuccess; -} - -/* - * SSL3 Utility functions - */ - -/* allowLargerPeerVersion controls whether the function will select the - * highest enabled SSL version or fail when peerVersion is greater than the - * highest enabled version. - * - * If allowLargerPeerVersion is true, peerVersion is the peer's highest - * enabled version rather than the peer's selected version. - */ -SECStatus -ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion, - PRBool allowLargerPeerVersion) -{ - if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - PORT_SetError(SSL_ERROR_SSL_DISABLED); - return SECFailure; - } - - if (peerVersion < ss->vrange.min || - (peerVersion > ss->vrange.max && !allowLargerPeerVersion)) { - PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); - return SECFailure; - } - - ss->version = PR_MIN(peerVersion, ss->vrange.max); - PORT_Assert(ssl3_VersionIsSupported(ss->protocolVariant, ss->version)); - - return SECSuccess; -} - -static SECStatus -ssl3_GetNewRandom(SSL3Random *random) -{ - SECStatus rv; - - rv = PK11_GenerateRandom(random->rand, SSL3_RANDOM_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); - } - return rv; -} - -/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */ -SECStatus -ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, - PRBool isTLS) -{ - SECStatus rv = SECFailure; - PRBool doDerEncode = PR_FALSE; - int signatureLen; - SECItem hashItem; - - buf->data = NULL; - - switch (key->keyType) { - case rsaKey: - hashItem.data = hash->u.raw; - hashItem.len = hash->len; - break; - case dsaKey: - doDerEncode = isTLS; - /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash. - * In that case, we use just the SHA1 part. */ - if (hash->hashAlg == ssl_hash_none) { - hashItem.data = hash->u.s.sha; - hashItem.len = sizeof(hash->u.s.sha); - } else { - hashItem.data = hash->u.raw; - hashItem.len = hash->len; - } - break; -#ifndef NSS_DISABLE_ECC - case ecKey: - doDerEncode = PR_TRUE; - /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash. - * In that case, we use just the SHA1 part. */ - if (hash->hashAlg == ssl_hash_none) { - hashItem.data = hash->u.s.sha; - hashItem.len = sizeof(hash->u.s.sha); - } else { - hashItem.data = hash->u.raw; - hashItem.len = hash->len; - } - break; -#endif /* NSS_DISABLE_ECC */ - default: - PORT_SetError(SEC_ERROR_INVALID_KEY); - goto done; - } - PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); - - if (hash->hashAlg == ssl_hash_none) { - signatureLen = PK11_SignatureLen(key); - if (signatureLen <= 0) { - PORT_SetError(SEC_ERROR_INVALID_KEY); - goto done; - } - - buf->len = (unsigned)signatureLen; - buf->data = (unsigned char *)PORT_Alloc(signatureLen); - if (!buf->data) - goto done; /* error code was set. */ - - rv = PK11_Sign(key, buf, &hashItem); - } else { - SECOidTag hashOID = ssl3_TLSHashAlgorithmToOID(hash->hashAlg); - rv = SGN_Digest(key, hashOID, buf, &hashItem); - } - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); - } else if (doDerEncode) { - SECItem derSig = { siBuffer, NULL, 0 }; - - /* This also works for an ECDSA signature */ - rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); - if (rv == SECSuccess) { - PORT_Free(buf->data); /* discard unencoded signature. */ - *buf = derSig; /* give caller encoded signature. */ - } else if (derSig.data) { - PORT_Free(derSig.data); - } - } - - PRINT_BUF(60, (NULL, "signed hashes", (unsigned char *)buf->data, buf->len)); -done: - if (rv != SECSuccess && buf->data) { - PORT_Free(buf->data); - buf->data = NULL; - } - return rv; -} - -/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */ -SECStatus -ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, - SECItem *buf, PRBool isTLS, void *pwArg) -{ - SECKEYPublicKey *key; - SECItem *signature = NULL; - SECStatus rv; - SECItem hashItem; - SECOidTag encAlg; - SECOidTag hashAlg; - - PRINT_BUF(60, (NULL, "check signed hashes", - buf->data, buf->len)); - - key = CERT_ExtractPublicKey(cert); - if (key == NULL) { - ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - return SECFailure; - } - - hashAlg = ssl3_TLSHashAlgorithmToOID(hash->hashAlg); - switch (key->keyType) { - case rsaKey: - encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; - hashItem.data = hash->u.raw; - hashItem.len = hash->len; - break; - case dsaKey: - encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; - /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash. - * In that case, we use just the SHA1 part. */ - if (hash->hashAlg == ssl_hash_none) { - hashItem.data = hash->u.s.sha; - hashItem.len = sizeof(hash->u.s.sha); - } else { - hashItem.data = hash->u.raw; - hashItem.len = hash->len; - } - /* Allow DER encoded DSA signatures in SSL 3.0 */ - if (isTLS || buf->len != SECKEY_SignatureLen(key)) { - signature = DSAU_DecodeDerSigToLen(buf, SECKEY_SignatureLen(key)); - if (!signature) { - PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); - return SECFailure; - } - buf = signature; - } - break; - -#ifndef NSS_DISABLE_ECC - case ecKey: - encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; - /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash. - * In that case, we use just the SHA1 part. - * ECDSA signatures always encode the integers r and s using ASN.1 - * (unlike DSA where ASN.1 encoding is used with TLS but not with - * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA. - */ - if (hash->hashAlg == ssl_hash_none) { - hashAlg = SEC_OID_SHA1; - hashItem.data = hash->u.s.sha; - hashItem.len = sizeof(hash->u.s.sha); - } else { - hashItem.data = hash->u.raw; - hashItem.len = hash->len; - } - break; -#endif /* NSS_DISABLE_ECC */ - - default: - SECKEY_DestroyPublicKey(key); - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); - return SECFailure; - } - - PRINT_BUF(60, (NULL, "hash(es) to be verified", - hashItem.data, hashItem.len)); - - if (hashAlg == SEC_OID_UNKNOWN || key->keyType == dsaKey) { - /* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded. - * DSA signatures are DER-encoded in TLS but not in SSL3 and the code - * above always removes the DER encoding of DSA signatures when - * present. Thus DSA signatures are always verified with PK11_Verify. - */ - rv = PK11_Verify(key, buf, &hashItem, pwArg); - } else { - rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg, - pwArg); - } - SECKEY_DestroyPublicKey(key); - if (signature) { - SECITEM_FreeItem(signature, PR_TRUE); - } - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); - } - return rv; -} - -/* Caller must set hiLevel error code. */ -/* Called from ssl3_ComputeExportRSAKeyHash - * ssl3_ComputeDHKeyHash - * which are called from ssl3_HandleServerKeyExchange. - * - * hashAlg: ssl_hash_none indicates the pre-1.2, MD5/SHA1 combination hash. - */ -SECStatus -ssl3_ComputeCommonKeyHash(SSLHashType hashAlg, - PRUint8 *hashBuf, unsigned int bufLen, - SSL3Hashes *hashes, PRBool bypassPKCS11) -{ - SECStatus rv; - SECOidTag hashOID; - -#ifndef NO_PKCS11_BYPASS - if (bypassPKCS11) { - if (hashAlg == ssl_hash_none) { - MD5_HashBuf(hashes->u.s.md5, hashBuf, bufLen); - SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen); - hashes->len = MD5_LENGTH + SHA1_LENGTH; - } else if (hashAlg == ssl_hash_sha1) { - SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen); - hashes->len = SHA1_LENGTH; - } else if (hashAlg == ssl_hash_sha256) { - SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen); - hashes->len = SHA256_LENGTH; - } else if (hashAlg == ssl_hash_sha384) { - SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen); - hashes->len = SHA384_LENGTH; - } else if (hashAlg == ssl_hash_sha512) { - SHA512_HashBuf(hashes->u.raw, hashBuf, bufLen); - hashes->len = SHA512_LENGTH; - } else { - PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); - return SECFailure; - } - } else -#endif - { - if (hashAlg == ssl_hash_none) { - rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return rv; - } - rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return rv; - } - hashes->len = MD5_LENGTH + SHA1_LENGTH; - } else { - hashOID = ssl3_TLSHashAlgorithmToOID(hashAlg); - hashes->len = HASH_ResultLenByOidTag(hashOID); - if (hashes->len == 0 || hashes->len > sizeof(hashes->u.raw)) { - ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); - return SECFailure; - } - rv = PK11_HashBuf(hashOID, hashes->u.raw, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - return rv; - } - } - } - hashes->hashAlg = hashAlg; - return SECSuccess; -} - -/* Caller must set hiLevel error code. -** Called from ssl3_SendServerKeyExchange and -** ssl3_HandleServerKeyExchange. -*/ -static SECStatus -ssl3_ComputeExportRSAKeyHash(SSLHashType hashAlg, - SECItem modulus, SECItem publicExponent, - SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes, PRBool bypassPKCS11) -{ - PRUint8 *hashBuf; - PRUint8 *pBuf; - SECStatus rv = SECSuccess; - unsigned int bufLen; - PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8]; - - bufLen = 2 * SSL3_RANDOM_LENGTH + 2 + modulus.len + 2 + publicExponent.len; - if (bufLen <= sizeof buf) { - hashBuf = buf; - } else { - hashBuf = PORT_Alloc(bufLen); - if (!hashBuf) { - return SECFailure; - } - } - - memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); - pBuf = hashBuf + SSL3_RANDOM_LENGTH; - memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); - pBuf += SSL3_RANDOM_LENGTH; - pBuf[0] = (PRUint8)(modulus.len >> 8); - pBuf[1] = (PRUint8)(modulus.len); - pBuf += 2; - memcpy(pBuf, modulus.data, modulus.len); - pBuf += modulus.len; - pBuf[0] = (PRUint8)(publicExponent.len >> 8); - pBuf[1] = (PRUint8)(publicExponent.len); - pBuf += 2; - memcpy(pBuf, publicExponent.data, publicExponent.len); - pBuf += publicExponent.len; - PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - - rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, - bypassPKCS11); - - PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen)); - if (hashAlg == ssl_hash_none) { - PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", - hashes->u.s.md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", - hashes->u.s.sha, SHA1_LENGTH)); - } else { - PRINT_BUF(95, (NULL, "RSAkey hash: result", - hashes->u.raw, hashes->len)); - } - - if (hashBuf != buf && hashBuf != NULL) - PORT_Free(hashBuf); - return rv; -} - -/* Caller must set hiLevel error code. */ -/* Called from ssl3_HandleServerKeyExchange. */ -static SECStatus -ssl3_ComputeDHKeyHash(SSLHashType hashAlg, - SECItem dh_p, SECItem dh_g, SECItem dh_Ys, - SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes, PRBool bypassPKCS11) -{ - PRUint8 *hashBuf; - PRUint8 *pBuf; - SECStatus rv = SECSuccess; - unsigned int bufLen; - PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8]; - - bufLen = 2 * SSL3_RANDOM_LENGTH + 2 + dh_p.len + 2 + dh_g.len + 2 + dh_Ys.len; - if (bufLen <= sizeof buf) { - hashBuf = buf; - } else { - hashBuf = PORT_Alloc(bufLen); - if (!hashBuf) { - return SECFailure; - } - } - - memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); - pBuf = hashBuf + SSL3_RANDOM_LENGTH; - memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); - pBuf += SSL3_RANDOM_LENGTH; - pBuf[0] = (PRUint8)(dh_p.len >> 8); - pBuf[1] = (PRUint8)(dh_p.len); - pBuf += 2; - memcpy(pBuf, dh_p.data, dh_p.len); - pBuf += dh_p.len; - pBuf[0] = (PRUint8)(dh_g.len >> 8); - pBuf[1] = (PRUint8)(dh_g.len); - pBuf += 2; - memcpy(pBuf, dh_g.data, dh_g.len); - pBuf += dh_g.len; - pBuf[0] = (PRUint8)(dh_Ys.len >> 8); - pBuf[1] = (PRUint8)(dh_Ys.len); - pBuf += 2; - memcpy(pBuf, dh_Ys.data, dh_Ys.len); - pBuf += dh_Ys.len; - PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - - rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, - bypassPKCS11); - - PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen)); - if (hashAlg == ssl_hash_none) { - PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", - hashes->u.s.md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", - hashes->u.s.sha, SHA1_LENGTH)); - } else { - PRINT_BUF(95, (NULL, "DHkey hash: result", - hashes->u.raw, hashes->len)); - } - - if (hashBuf != buf && hashBuf != NULL) - PORT_Free(hashBuf); - return rv; -} - -void -ssl3_BumpSequenceNumber(SSL3SequenceNumber *num) -{ - num->low++; - if (num->low == 0) - num->high++; -} - -/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */ -static void -ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) -{ - if (mat->write_key != NULL) { - PK11_FreeSymKey(mat->write_key); - mat->write_key = NULL; - } - if (mat->write_mac_key != NULL) { - PK11_FreeSymKey(mat->write_mac_key); - mat->write_mac_key = NULL; - } - if (mat->write_mac_context != NULL) { - PK11_DestroyContext(mat->write_mac_context, PR_TRUE); - mat->write_mac_context = NULL; - } -} - -/* Called from ssl3_SendChangeCipherSpecs() and -** ssl3_HandleChangeCipherSpecs() -** ssl3_DestroySSL3Info -** Caller must hold SpecWriteLock. -*/ -void -ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) -{ - PRBool freeit = (PRBool)(!spec->bypassCiphers); - /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ - if (spec->destroy) { - spec->destroy(spec->encodeContext, freeit); - spec->destroy(spec->decodeContext, freeit); - spec->encodeContext = NULL; /* paranoia */ - spec->decodeContext = NULL; - } - if (spec->destroyCompressContext && spec->compressContext) { - spec->destroyCompressContext(spec->compressContext, 1); - spec->compressContext = NULL; - } - if (spec->destroyDecompressContext && spec->decompressContext) { - spec->destroyDecompressContext(spec->decompressContext, 1); - spec->decompressContext = NULL; - } - if (freeSrvName && spec->srvVirtName.data) { - SECITEM_FreeItem(&spec->srvVirtName, PR_FALSE); - } - if (spec->master_secret != NULL) { - PK11_FreeSymKey(spec->master_secret); - spec->master_secret = NULL; - } - spec->msItem.data = NULL; - spec->msItem.len = 0; - ssl3_CleanupKeyMaterial(&spec->client); - ssl3_CleanupKeyMaterial(&spec->server); - spec->bypassCiphers = PR_FALSE; - spec->destroy = NULL; - spec->destroyCompressContext = NULL; - spec->destroyDecompressContext = NULL; -} - -/* Fill in the pending cipher spec with info from the selected ciphersuite. -** This is as much initialization as we can do without having key material. -** Called from ssl3_HandleServerHello(), ssl3_SendServerHello() -** Caller must hold the ssl3 handshake lock. -** Acquires & releases SpecWriteLock. -*/ -SECStatus -ssl3_SetupPendingCipherSpec(sslSocket *ss) -{ - ssl3CipherSpec *pwSpec; - ssl3CipherSpec *cwSpec; - ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite; - SSL3MACAlgorithm mac; - SSL3BulkCipher cipher; - SSL3KeyExchangeAlgorithm kea; - const ssl3CipherSuiteDef *suite_def; - PRBool isTLS; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - ssl_GetSpecWriteLock(ss); /*******************************/ - - pwSpec = ss->ssl3.pwSpec; - PORT_Assert(pwSpec == ss->ssl3.prSpec); - - /* This hack provides maximal interoperability with SSL 3 servers. */ - cwSpec = ss->ssl3.cwSpec; - if (cwSpec->mac_def->mac == mac_null) { - /* SSL records are not being MACed. */ - cwSpec->version = ss->version; - } - - pwSpec->version = ss->version; - isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0); - - SSL_TRC(3, ("%d: SSL3[%d]: Set XXX Pending Cipher Suite to 0x%04x", - SSL_GETPID(), ss->fd, suite)); - - suite_def = ssl_LookupCipherSuiteDef(suite); - if (suite_def == NULL) { - ssl_ReleaseSpecWriteLock(ss); - return SECFailure; /* error code set by ssl_LookupCipherSuiteDef */ - } - - if (IS_DTLS(ss)) { - /* Double-check that we did not pick an RC4 suite */ - PORT_Assert((suite_def->bulk_cipher_alg != cipher_rc4) && - (suite_def->bulk_cipher_alg != cipher_rc4_40) && - (suite_def->bulk_cipher_alg != cipher_rc4_56)); - } - - cipher = suite_def->bulk_cipher_alg; - kea = suite_def->key_exchange_alg; - mac = suite_def->mac_alg; - if (mac <= ssl_mac_sha && mac != ssl_mac_null && isTLS) - mac += 2; - - ss->ssl3.hs.suite_def = suite_def; - ss->ssl3.hs.kea_def = &kea_defs[kea]; - PORT_Assert(ss->ssl3.hs.kea_def->kea == kea); - - pwSpec->cipher_def = &bulk_cipher_defs[cipher]; - PORT_Assert(pwSpec->cipher_def->cipher == cipher); - - pwSpec->mac_def = &mac_defs[mac]; - PORT_Assert(pwSpec->mac_def->mac == mac); - - ss->sec.keyBits = pwSpec->cipher_def->key_size * BPB; - ss->sec.secretKeyBits = pwSpec->cipher_def->secret_key_size * BPB; - ss->sec.cipherType = cipher; - - pwSpec->encodeContext = NULL; - pwSpec->decodeContext = NULL; - - pwSpec->mac_size = pwSpec->mac_def->mac_size; - - pwSpec->compression_method = ss->ssl3.hs.compression; - pwSpec->compressContext = NULL; - pwSpec->decompressContext = NULL; - - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - PORT_Assert(ss->ssl3.hs.kea_def->ephemeral); - PORT_Assert(pwSpec->cipher_def->type == type_aead); - } - ssl_ReleaseSpecWriteLock(ss); /*******************************/ - return SECSuccess; -} - -#ifdef NSS_SSL_ENABLE_ZLIB -#define SSL3_DEFLATE_CONTEXT_SIZE sizeof(z_stream) - -static SECStatus -ssl3_MapZlibError(int zlib_error) -{ - switch (zlib_error) { - case Z_OK: - return SECSuccess; - default: - return SECFailure; - } -} - -static SECStatus -ssl3_DeflateInit(void *void_context) -{ - z_stream *context = void_context; - context->zalloc = NULL; - context->zfree = NULL; - context->opaque = NULL; - - return ssl3_MapZlibError(deflateInit(context, Z_DEFAULT_COMPRESSION)); -} - -static SECStatus -ssl3_InflateInit(void *void_context) -{ - z_stream *context = void_context; - context->zalloc = NULL; - context->zfree = NULL; - context->opaque = NULL; - context->next_in = NULL; - context->avail_in = 0; - - return ssl3_MapZlibError(inflateInit(context)); -} - -static SECStatus -ssl3_DeflateCompress(void *void_context, unsigned char *out, int *out_len, - int maxout, const unsigned char *in, int inlen) -{ - z_stream *context = void_context; - - if (!inlen) { - *out_len = 0; - return SECSuccess; - } - - context->next_in = (unsigned char *)in; - context->avail_in = inlen; - context->next_out = out; - context->avail_out = maxout; - if (deflate(context, Z_SYNC_FLUSH) != Z_OK) { - return SECFailure; - } - if (context->avail_out == 0) { - /* We ran out of space! */ - SSL_TRC(3, ("%d: SSL3[%d] Ran out of buffer while compressing", - SSL_GETPID())); - return SECFailure; - } - - *out_len = maxout - context->avail_out; - return SECSuccess; -} - -static SECStatus -ssl3_DeflateDecompress(void *void_context, unsigned char *out, int *out_len, - int maxout, const unsigned char *in, int inlen) -{ - z_stream *context = void_context; - - if (!inlen) { - *out_len = 0; - return SECSuccess; - } - - context->next_in = (unsigned char *)in; - context->avail_in = inlen; - context->next_out = out; - context->avail_out = maxout; - if (inflate(context, Z_SYNC_FLUSH) != Z_OK) { - PORT_SetError(SSL_ERROR_DECOMPRESSION_FAILURE); - return SECFailure; - } - - *out_len = maxout - context->avail_out; - return SECSuccess; -} - -static SECStatus -ssl3_DestroyCompressContext(void *void_context, PRBool unused) -{ - deflateEnd(void_context); - PORT_Free(void_context); - return SECSuccess; -} - -static SECStatus -ssl3_DestroyDecompressContext(void *void_context, PRBool unused) -{ - inflateEnd(void_context); - PORT_Free(void_context); - return SECSuccess; -} - -#endif /* NSS_SSL_ENABLE_ZLIB */ - -/* Initialize the compression functions and contexts for the given - * CipherSpec. */ -static SECStatus -ssl3_InitCompressionContext(ssl3CipherSpec *pwSpec) -{ - /* Setup the compression functions */ - switch (pwSpec->compression_method) { - case ssl_compression_null: - pwSpec->compressor = NULL; - pwSpec->decompressor = NULL; - pwSpec->compressContext = NULL; - pwSpec->decompressContext = NULL; - pwSpec->destroyCompressContext = NULL; - pwSpec->destroyDecompressContext = NULL; - break; -#ifdef NSS_SSL_ENABLE_ZLIB - case ssl_compression_deflate: - pwSpec->compressor = ssl3_DeflateCompress; - pwSpec->decompressor = ssl3_DeflateDecompress; - pwSpec->compressContext = PORT_Alloc(SSL3_DEFLATE_CONTEXT_SIZE); - pwSpec->decompressContext = PORT_Alloc(SSL3_DEFLATE_CONTEXT_SIZE); - pwSpec->destroyCompressContext = ssl3_DestroyCompressContext; - pwSpec->destroyDecompressContext = ssl3_DestroyDecompressContext; - ssl3_DeflateInit(pwSpec->compressContext); - ssl3_InflateInit(pwSpec->decompressContext); - break; -#endif /* NSS_SSL_ENABLE_ZLIB */ - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - return SECSuccess; -} - -#ifndef NO_PKCS11_BYPASS -/* Initialize encryption contexts for pending spec. - * MAC contexts are set up when computing the mac, not here. - * Master Secret already is derived in spec->msItem - * Caller holds Spec write lock. - */ -static SECStatus -ssl3_InitPendingContextsBypass(sslSocket *ss) -{ - ssl3CipherSpec *pwSpec; - const ssl3BulkCipherDef *cipher_def; - void *serverContext = NULL; - void *clientContext = NULL; - BLapiInitContextFunc initFn = (BLapiInitContextFunc)NULL; - int mode = 0; - unsigned int optArg1 = 0; - unsigned int optArg2 = 0; - PRBool server_encrypts = ss->sec.isServer; - SSLCipherAlgorithm calg; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - pwSpec = ss->ssl3.pwSpec; - cipher_def = pwSpec->cipher_def; - - calg = cipher_def->calg; - - if (calg == ssl_calg_aes_gcm) { - pwSpec->encode = NULL; - pwSpec->decode = NULL; - pwSpec->destroy = NULL; - pwSpec->encodeContext = NULL; - pwSpec->decodeContext = NULL; - pwSpec->aead = ssl3_AESGCMBypass; - ssl3_InitCompressionContext(pwSpec); - return SECSuccess; - } - - serverContext = pwSpec->server.cipher_context; - clientContext = pwSpec->client.cipher_context; - - switch (calg) { - case ssl_calg_null: - pwSpec->encode = Null_Cipher; - pwSpec->decode = Null_Cipher; - pwSpec->destroy = NULL; - goto success; - - case ssl_calg_rc4: - initFn = (BLapiInitContextFunc)RC4_InitContext; - pwSpec->encode = (SSLCipher)RC4_Encrypt; - pwSpec->decode = (SSLCipher)RC4_Decrypt; - pwSpec->destroy = (SSLDestroy)RC4_DestroyContext; - break; - case ssl_calg_rc2: - initFn = (BLapiInitContextFunc)RC2_InitContext; - mode = NSS_RC2_CBC; - optArg1 = cipher_def->key_size; - pwSpec->encode = (SSLCipher)RC2_Encrypt; - pwSpec->decode = (SSLCipher)RC2_Decrypt; - pwSpec->destroy = (SSLDestroy)RC2_DestroyContext; - break; - case ssl_calg_des: - initFn = (BLapiInitContextFunc)DES_InitContext; - mode = NSS_DES_CBC; - optArg1 = server_encrypts; - pwSpec->encode = (SSLCipher)DES_Encrypt; - pwSpec->decode = (SSLCipher)DES_Decrypt; - pwSpec->destroy = (SSLDestroy)DES_DestroyContext; - break; - case ssl_calg_3des: - initFn = (BLapiInitContextFunc)DES_InitContext; - mode = NSS_DES_EDE3_CBC; - optArg1 = server_encrypts; - pwSpec->encode = (SSLCipher)DES_Encrypt; - pwSpec->decode = (SSLCipher)DES_Decrypt; - pwSpec->destroy = (SSLDestroy)DES_DestroyContext; - break; - case ssl_calg_aes: - initFn = (BLapiInitContextFunc)AES_InitContext; - mode = NSS_AES_CBC; - optArg1 = server_encrypts; - optArg2 = AES_BLOCK_SIZE; - pwSpec->encode = (SSLCipher)AES_Encrypt; - pwSpec->decode = (SSLCipher)AES_Decrypt; - pwSpec->destroy = (SSLDestroy)AES_DestroyContext; - break; - - case ssl_calg_camellia: - initFn = (BLapiInitContextFunc)Camellia_InitContext; - mode = NSS_CAMELLIA_CBC; - optArg1 = server_encrypts; - optArg2 = CAMELLIA_BLOCK_SIZE; - pwSpec->encode = (SSLCipher)Camellia_Encrypt; - pwSpec->decode = (SSLCipher)Camellia_Decrypt; - pwSpec->destroy = (SSLDestroy)Camellia_DestroyContext; - break; - - case ssl_calg_seed: - initFn = (BLapiInitContextFunc)SEED_InitContext; - mode = NSS_SEED_CBC; - optArg1 = server_encrypts; - optArg2 = SEED_BLOCK_SIZE; - pwSpec->encode = (SSLCipher)SEED_Encrypt; - pwSpec->decode = (SSLCipher)SEED_Decrypt; - pwSpec->destroy = (SSLDestroy)SEED_DestroyContext; - break; - - case ssl_calg_idea: - case ssl_calg_fortezza: - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - goto bail_out; - } - rv = (*initFn)(serverContext, - pwSpec->server.write_key_item.data, - pwSpec->server.write_key_item.len, - pwSpec->server.write_iv_item.data, - mode, optArg1, optArg2); - if (rv != SECSuccess) { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - goto bail_out; - } - - switch (calg) { - case ssl_calg_des: - case ssl_calg_3des: - case ssl_calg_aes: - case ssl_calg_camellia: - case ssl_calg_seed: - /* For block ciphers, if the server is encrypting, then the client - * is decrypting, and vice versa. - */ - optArg1 = !optArg1; - break; - /* kill warnings. */ - case ssl_calg_null: - case ssl_calg_rc4: - case ssl_calg_rc2: - case ssl_calg_idea: - case ssl_calg_fortezza: - case ssl_calg_aes_gcm: - case ssl_calg_chacha20: - break; - } - - rv = (*initFn)(clientContext, - pwSpec->client.write_key_item.data, - pwSpec->client.write_key_item.len, - pwSpec->client.write_iv_item.data, - mode, optArg1, optArg2); - if (rv != SECSuccess) { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - goto bail_out; - } - - pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext; - pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext; - - ssl3_InitCompressionContext(pwSpec); - -success: - return SECSuccess; - -bail_out: - return SECFailure; -} -#endif - -/* This function should probably be moved to pk11wrap and be named - * PK11_ParamFromIVAndEffectiveKeyBits - */ -static SECItem * -ssl3_ParamFromIV(CK_MECHANISM_TYPE mtype, SECItem *iv, CK_ULONG ulEffectiveBits) -{ - SECItem *param = PK11_ParamFromIV(mtype, iv); - if (param && param->data && param->len >= sizeof(CK_RC2_PARAMS)) { - switch (mtype) { - case CKM_RC2_KEY_GEN: - case CKM_RC2_ECB: - case CKM_RC2_CBC: - case CKM_RC2_MAC: - case CKM_RC2_MAC_GENERAL: - case CKM_RC2_CBC_PAD: - *(CK_RC2_PARAMS *)param->data = ulEffectiveBits; - default: - break; - } - } - return param; -} - -/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data - * which is included in the MAC or AEAD additional data) to |out| and returns - * its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the - * definition of the AEAD additional data. - * - * TLS pseudo-header includes the record's version field, SSL's doesn't. Which - * pseudo-header defintiion to use should be decided based on the version of - * the protocol that was negotiated when the cipher spec became current, NOT - * based on the version value in the record itself, and the decision is passed - * to this function as the |includesVersion| argument. But, the |version| - * argument should be the record's version value. - */ -static unsigned int -ssl3_BuildRecordPseudoHeader(unsigned char *out, - SSL3SequenceNumber seq_num, - SSL3ContentType type, - PRBool includesVersion, - SSL3ProtocolVersion version, - PRBool isDTLS, - int length) -{ - out[0] = (unsigned char)(seq_num.high >> 24); - out[1] = (unsigned char)(seq_num.high >> 16); - out[2] = (unsigned char)(seq_num.high >> 8); - out[3] = (unsigned char)(seq_num.high >> 0); - out[4] = (unsigned char)(seq_num.low >> 24); - out[5] = (unsigned char)(seq_num.low >> 16); - out[6] = (unsigned char)(seq_num.low >> 8); - out[7] = (unsigned char)(seq_num.low >> 0); - out[8] = type; - - /* SSL3 MAC doesn't include the record's version field. */ - if (!includesVersion) { - out[9] = MSB(length); - out[10] = LSB(length); - return 11; - } - - /* TLS MAC and AEAD additional data include version. */ - if (isDTLS) { - SSL3ProtocolVersion dtls_version; - - dtls_version = dtls_TLSVersionToDTLSVersion(version); - out[9] = MSB(dtls_version); - out[10] = LSB(dtls_version); - } else { - out[9] = MSB(version); - out[10] = LSB(version); - } - out[11] = MSB(length); - out[12] = LSB(length); - return 13; -} - -static SECStatus -ssl3_AESGCM(ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen, - const unsigned char *additionalData, - int additionalDataLen) -{ - SECItem param; - SECStatus rv = SECFailure; - unsigned char nonce[12]; - unsigned int uOutLen; - CK_GCM_PARAMS gcmParams; - - const int tagSize = bulk_cipher_defs[cipher_aes_128_gcm].tag_size; - const int explicitNonceLen = - bulk_cipher_defs[cipher_aes_128_gcm].explicit_nonce_size; - - /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the - * nonce is formed. */ - memcpy(nonce, keys->write_iv, 4); - if (doDecrypt) { - memcpy(nonce + 4, in, explicitNonceLen); - in += explicitNonceLen; - inlen -= explicitNonceLen; - *outlen = 0; - } else { - if (maxout < explicitNonceLen) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - return SECFailure; - } - /* Use the 64-bit sequence number as the explicit nonce. */ - memcpy(nonce + 4, additionalData, explicitNonceLen); - memcpy(out, additionalData, explicitNonceLen); - out += explicitNonceLen; - maxout -= explicitNonceLen; - *outlen = explicitNonceLen; - } - - param.type = siBuffer; - param.data = (unsigned char *)&gcmParams; - param.len = sizeof(gcmParams); - gcmParams.pIv = nonce; - gcmParams.ulIvLen = sizeof(nonce); - gcmParams.pAAD = (unsigned char *)additionalData; /* const cast */ - gcmParams.ulAADLen = additionalDataLen; - gcmParams.ulTagBits = tagSize * 8; - - if (doDecrypt) { - rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, - maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, - maxout, in, inlen); - } - *outlen += (int)uOutLen; - - return rv; -} - -#ifndef NO_PKCS11_BYPASS -static SECStatus -ssl3_AESGCMBypass(ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen, - const unsigned char *additionalData, - int additionalDataLen) -{ - SECStatus rv = SECFailure; - unsigned char nonce[12]; - unsigned int uOutLen; - AESContext *cx; - CK_GCM_PARAMS gcmParams; - - const int tagSize = bulk_cipher_defs[cipher_aes_128_gcm].tag_size; - const int explicitNonceLen = - bulk_cipher_defs[cipher_aes_128_gcm].explicit_nonce_size; - - /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the - * nonce is formed. */ - PORT_Assert(keys->write_iv_item.len == 4); - if (keys->write_iv_item.len != 4) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - memcpy(nonce, keys->write_iv_item.data, 4); - if (doDecrypt) { - memcpy(nonce + 4, in, explicitNonceLen); - in += explicitNonceLen; - inlen -= explicitNonceLen; - *outlen = 0; - } else { - if (maxout < explicitNonceLen) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - return SECFailure; - } - /* Use the 64-bit sequence number as the explicit nonce. */ - memcpy(nonce + 4, additionalData, explicitNonceLen); - memcpy(out, additionalData, explicitNonceLen); - out += explicitNonceLen; - maxout -= explicitNonceLen; - *outlen = explicitNonceLen; - } - - gcmParams.pIv = nonce; - gcmParams.ulIvLen = sizeof(nonce); - gcmParams.pAAD = (unsigned char *)additionalData; /* const cast */ - gcmParams.ulAADLen = additionalDataLen; - gcmParams.ulTagBits = tagSize * 8; - - cx = (AESContext *)keys->cipher_context; - rv = AES_InitContext(cx, keys->write_key_item.data, - keys->write_key_item.len, - (unsigned char *)&gcmParams, NSS_AES_GCM, !doDecrypt, - AES_BLOCK_SIZE); - if (rv != SECSuccess) { - return rv; - } - if (doDecrypt) { - rv = AES_Decrypt(cx, out, &uOutLen, maxout, in, inlen); - } else { - rv = AES_Encrypt(cx, out, &uOutLen, maxout, in, inlen); - } - AES_DestroyContext(cx, PR_FALSE); - *outlen += (int)uOutLen; - - return rv; -} -#endif - -static SECStatus -ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, - unsigned char *out, int *outlen, int maxout, - const unsigned char *in, int inlen, - const unsigned char *additionalData, - int additionalDataLen) -{ - size_t i; - SECItem param; - SECStatus rv = SECFailure; - unsigned int uOutLen; - unsigned char nonce[12]; - CK_NSS_AEAD_PARAMS aeadParams; - - const int tagSize = bulk_cipher_defs[cipher_chacha20].tag_size; - - /* See - * https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2 - * for details of how the nonce is formed. */ - PORT_Memcpy(nonce, keys->write_iv, 12); - - /* XOR the last 8 bytes of the IV with the sequence number. */ - PORT_Assert(additionalDataLen >= 8); - for (i = 0; i < 8; ++i) { - nonce[4 + i] ^= additionalData[i]; - } - - param.type = siBuffer; - param.len = sizeof(aeadParams); - param.data = (unsigned char *)&aeadParams; - memset(&aeadParams, 0, sizeof(aeadParams)); - aeadParams.pNonce = nonce; - aeadParams.ulNonceLen = sizeof(nonce); - aeadParams.pAAD = (unsigned char *)additionalData; - aeadParams.ulAADLen = additionalDataLen; - aeadParams.ulTagLen = tagSize; - - if (doDecrypt) { - rv = PK11_Decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, - out, &uOutLen, maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, - out, &uOutLen, maxout, in, inlen); - } - *outlen = (int)uOutLen; - - return rv; -} - -/* Initialize encryption and MAC contexts for pending spec. - * Master Secret already is derived. - * Caller holds Spec write lock. - */ -static SECStatus -ssl3_InitPendingContextsPKCS11(sslSocket *ss) -{ - ssl3CipherSpec *pwSpec; - const ssl3BulkCipherDef *cipher_def; - PK11Context *serverContext = NULL; - PK11Context *clientContext = NULL; - SECItem *param; - CK_MECHANISM_TYPE mechanism; - CK_MECHANISM_TYPE mac_mech; - CK_ULONG macLength; - CK_ULONG effKeyBits; - SECItem iv; - SECItem mac_param; - SSLCipherAlgorithm calg; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - pwSpec = ss->ssl3.pwSpec; - cipher_def = pwSpec->cipher_def; - macLength = pwSpec->mac_size; - calg = cipher_def->calg; - PORT_Assert(alg2Mech[calg].calg == calg); - - pwSpec->client.write_mac_context = NULL; - pwSpec->server.write_mac_context = NULL; - - if (cipher_def->type == type_aead) { - pwSpec->encode = NULL; - pwSpec->decode = NULL; - pwSpec->destroy = NULL; - pwSpec->encodeContext = NULL; - pwSpec->decodeContext = NULL; - switch (calg) { - case calg_aes_gcm: - pwSpec->aead = ssl3_AESGCM; - break; - case calg_chacha20: - pwSpec->aead = ssl3_ChaCha20Poly1305; - break; - default: - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - return SECSuccess; - } - - /* - ** Now setup the MAC contexts, - ** crypto contexts are setup below. - */ - - mac_mech = pwSpec->mac_def->mmech; - mac_param.data = (unsigned char *)&macLength; - mac_param.len = sizeof(macLength); - mac_param.type = 0; - - pwSpec->client.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->client.write_mac_key, &mac_param); - if (pwSpec->client.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - pwSpec->server.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->server.write_mac_key, &mac_param); - if (pwSpec->server.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - - /* - ** Now setup the crypto contexts. - */ - - if (calg == calg_null) { - pwSpec->encode = Null_Cipher; - pwSpec->decode = Null_Cipher; - pwSpec->destroy = NULL; - return SECSuccess; - } - mechanism = ssl3_Alg2Mech(calg); - effKeyBits = cipher_def->key_size * BPB; - - /* - * build the server context - */ - iv.data = pwSpec->server.write_iv; - iv.len = cipher_def->iv_size; - param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits); - if (param == NULL) { - ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); - goto fail; - } - serverContext = PK11_CreateContextBySymKey(mechanism, - (ss->sec.isServer ? CKA_ENCRYPT - : CKA_DECRYPT), - pwSpec->server.write_key, param); - iv.data = PK11_IVFromParam(mechanism, param, (int *)&iv.len); - if (iv.data) - PORT_Memcpy(pwSpec->server.write_iv, iv.data, iv.len); - SECITEM_FreeItem(param, PR_TRUE); - if (serverContext == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - - /* - * build the client context - */ - iv.data = pwSpec->client.write_iv; - iv.len = cipher_def->iv_size; - - param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits); - if (param == NULL) { - ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); - goto fail; - } - clientContext = PK11_CreateContextBySymKey(mechanism, - (ss->sec.isServer ? CKA_DECRYPT - : CKA_ENCRYPT), - pwSpec->client.write_key, param); - iv.data = PK11_IVFromParam(mechanism, param, (int *)&iv.len); - if (iv.data) - PORT_Memcpy(pwSpec->client.write_iv, iv.data, iv.len); - SECITEM_FreeItem(param, PR_TRUE); - if (clientContext == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - pwSpec->encode = (SSLCipher)PK11_CipherOp; - pwSpec->decode = (SSLCipher)PK11_CipherOp; - pwSpec->destroy = (SSLDestroy)PK11_DestroyContext; - - pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext; - pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext; - - serverContext = NULL; - clientContext = NULL; - - ssl3_InitCompressionContext(pwSpec); - - return SECSuccess; - -fail: - if (serverContext != NULL) - PK11_DestroyContext(serverContext, PR_TRUE); - if (clientContext != NULL) - PK11_DestroyContext(clientContext, PR_TRUE); - if (pwSpec->client.write_mac_context != NULL) { - PK11_DestroyContext(pwSpec->client.write_mac_context, PR_TRUE); - pwSpec->client.write_mac_context = NULL; - } - if (pwSpec->server.write_mac_context != NULL) { - PK11_DestroyContext(pwSpec->server.write_mac_context, PR_TRUE); - pwSpec->server.write_mac_context = NULL; - } - - return SECFailure; -} - -#ifndef NO_PKCS11_BYPASS -/* Returns whether we can bypass PKCS#11 for a given cipher algorithm. - * - * We do not support PKCS#11 bypass for ChaCha20/Poly1305. - */ -static PRBool -ssl3_CanBypassCipher(SSLCipherAlgorithm calg) -{ - switch (calg) { - case calg_chacha20: - return PR_FALSE; - default: - return PR_TRUE; - } -} -#endif - -/* Complete the initialization of all keys, ciphers, MACs and their contexts - * for the pending Cipher Spec. - * Called from: ssl3_SendClientKeyExchange (for Full handshake) - * ssl3_HandleRSAClientKeyExchange (for Full handshake) - * ssl3_HandleServerHello (for session restart) - * ssl3_HandleClientHello (for session restart) - * Sets error code, but caller probably should override to disambiguate. - * NULL pms means re-use old master_secret. - * - * This code is common to the bypass and PKCS11 execution paths. For - * the bypass case, pms is NULL. If the old master secret is reused, - * pms is NULL and the master secret is already in either - * pwSpec->msItem.len (the bypass case) or pwSpec->master_secret. - * - * For the bypass case, pms is NULL. - */ -SECStatus -ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) -{ - ssl3CipherSpec *pwSpec; - ssl3CipherSpec *cwSpec; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - ssl_GetSpecWriteLock(ss); /**************************************/ - - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - pwSpec = ss->ssl3.pwSpec; - cwSpec = ss->ssl3.cwSpec; - - if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) { - rv = ssl3_DeriveMasterSecret(ss, pms); - if (rv != SECSuccess) { - goto done; /* err code set by ssl3_DeriveMasterSecret */ - } - } -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11 && pwSpec->msItem.len && pwSpec->msItem.data && - ssl3_CanBypassCipher(ss->ssl3.pwSpec->cipher_def->calg)) { - /* Double Bypass succeeded in extracting the master_secret */ - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; - PRBool isTLS = (PRBool)(kea_def->tls_keygen || - (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); - pwSpec->bypassCiphers = PR_TRUE; - rv = ssl3_KeyAndMacDeriveBypass(pwSpec, - (const unsigned char *)&ss->ssl3.hs.client_random, - (const unsigned char *)&ss->ssl3.hs.server_random, - isTLS, - (PRBool)(kea_def->is_limited)); - if (rv == SECSuccess) { - rv = ssl3_InitPendingContextsBypass(ss); - } - } else -#endif - if (pwSpec->master_secret) { - rv = ssl3_DeriveConnectionKeysPKCS11(ss); - if (rv == SECSuccess) { - rv = ssl3_InitPendingContextsPKCS11(ss); - } - } else { - PORT_Assert(pwSpec->master_secret); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } - if (rv != SECSuccess) { - goto done; - } - - /* Generic behaviors -- common to all crypto methods */ - if (!IS_DTLS(ss)) { - pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0; - } else { - if (cwSpec->epoch == PR_UINT16_MAX) { - /* The problem here is that we have rehandshaked too many - * times (you are not allowed to wrap the epoch). The - * spec says you should be discarding the connection - * and start over, so not much we can do here. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - goto done; - } - /* The sequence number has the high 16 bits as the epoch. */ - pwSpec->epoch = cwSpec->epoch + 1; - pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = - pwSpec->epoch << 16; - - dtls_InitRecvdRecords(&pwSpec->recvdRecords); - } - pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0; - -done: - ssl_ReleaseSpecWriteLock(ss); /******************************/ - if (rv != SECSuccess) - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return rv; -} - -/* - * 60 bytes is 3 times the maximum length MAC size that is supported. - */ -static const unsigned char mac_pad_1[60] = { - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36 -}; -static const unsigned char mac_pad_2[60] = { - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5c, 0x5c, 0x5c -}; - -/* Called from: ssl3_SendRecord() -** Caller must already hold the SpecReadLock. (wish we could assert that!) -*/ -static SECStatus -ssl3_ComputeRecordMAC( - ssl3CipherSpec *spec, - PRBool useServerMacKey, - const unsigned char *header, - unsigned int headerLen, - const SSL3Opaque *input, - int inputLength, - unsigned char *outbuf, - unsigned int *outLength) -{ - const ssl3MACDef *mac_def; - SECStatus rv; - - PRINT_BUF(95, (NULL, "frag hash1: header", header, headerLen)); - PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength)); - - mac_def = spec->mac_def; - if (mac_def->mac == mac_null) { - *outLength = 0; - return SECSuccess; - } -#ifndef NO_PKCS11_BYPASS - if (spec->bypassCiphers) { - /* bypass version */ - const SECHashObject *hashObj = NULL; - unsigned int pad_bytes = 0; - PRUint64 write_mac_context[MAX_MAC_CONTEXT_LLONGS]; - - switch (mac_def->mac) { - case ssl_mac_null: - *outLength = 0; - return SECSuccess; - case ssl_mac_md5: - pad_bytes = 48; - hashObj = HASH_GetRawHashObject(HASH_AlgMD5); - break; - case ssl_mac_sha: - pad_bytes = 40; - hashObj = HASH_GetRawHashObject(HASH_AlgSHA1); - break; - case ssl_hmac_md5: /* used with TLS */ - hashObj = HASH_GetRawHashObject(HASH_AlgMD5); - break; - case ssl_hmac_sha: /* used with TLS */ - hashObj = HASH_GetRawHashObject(HASH_AlgSHA1); - break; - case ssl_hmac_sha256: /* used with TLS */ - hashObj = HASH_GetRawHashObject(HASH_AlgSHA256); - break; - default: - break; - } - if (!hashObj) { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - if (spec->version <= SSL_LIBRARY_VERSION_3_0) { - unsigned int tempLen; - unsigned char temp[MAX_MAC_LENGTH]; - - /* compute "inner" part of SSL3 MAC */ - hashObj->begin(write_mac_context); - if (useServerMacKey) - hashObj->update(write_mac_context, - spec->server.write_mac_key_item.data, - spec->server.write_mac_key_item.len); - else - hashObj->update(write_mac_context, - spec->client.write_mac_key_item.data, - spec->client.write_mac_key_item.len); - hashObj->update(write_mac_context, mac_pad_1, pad_bytes); - hashObj->update(write_mac_context, header, headerLen); - hashObj->update(write_mac_context, input, inputLength); - hashObj->end(write_mac_context, temp, &tempLen, sizeof temp); - - /* compute "outer" part of SSL3 MAC */ - hashObj->begin(write_mac_context); - if (useServerMacKey) - hashObj->update(write_mac_context, - spec->server.write_mac_key_item.data, - spec->server.write_mac_key_item.len); - else - hashObj->update(write_mac_context, - spec->client.write_mac_key_item.data, - spec->client.write_mac_key_item.len); - hashObj->update(write_mac_context, mac_pad_2, pad_bytes); - hashObj->update(write_mac_context, temp, tempLen); - hashObj->end(write_mac_context, outbuf, outLength, spec->mac_size); - rv = SECSuccess; - } else { /* is TLS */ -#define cx ((HMACContext *)write_mac_context) - if (useServerMacKey) { - rv = HMAC_Init(cx, hashObj, - spec->server.write_mac_key_item.data, - spec->server.write_mac_key_item.len, PR_FALSE); - } else { - rv = HMAC_Init(cx, hashObj, - spec->client.write_mac_key_item.data, - spec->client.write_mac_key_item.len, PR_FALSE); - } - if (rv == SECSuccess) { - HMAC_Begin(cx); - HMAC_Update(cx, header, headerLen); - HMAC_Update(cx, input, inputLength); - rv = HMAC_Finish(cx, outbuf, outLength, spec->mac_size); - HMAC_Destroy(cx, PR_FALSE); - } -#undef cx - } - } else -#endif - { - PK11Context *mac_context = - (useServerMacKey ? spec->server.write_mac_context - : spec->client.write_mac_context); - rv = PK11_DigestBegin(mac_context); - rv |= PK11_DigestOp(mac_context, header, headerLen); - rv |= PK11_DigestOp(mac_context, input, inputLength); - rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size); - } - - PORT_Assert(rv != SECSuccess || *outLength == (unsigned)spec->mac_size); - - PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLength)); - - if (rv != SECSuccess) { - rv = SECFailure; - ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); - } - return rv; -} - -/* Called from: ssl3_HandleRecord() - * Caller must already hold the SpecReadLock. (wish we could assert that!) - * - * On entry: - * originalLen >= inputLen >= MAC size -*/ -static SECStatus -ssl3_ComputeRecordMACConstantTime( - ssl3CipherSpec *spec, - PRBool useServerMacKey, - const unsigned char *header, - unsigned int headerLen, - const SSL3Opaque *input, - int inputLen, - int originalLen, - unsigned char *outbuf, - unsigned int *outLen) -{ - CK_MECHANISM_TYPE macType; - CK_NSS_MAC_CONSTANT_TIME_PARAMS params; - SECItem param, inputItem, outputItem; - SECStatus rv; - PK11SymKey *key; - - PORT_Assert(inputLen >= spec->mac_size); - PORT_Assert(originalLen >= inputLen); - - if (spec->bypassCiphers) { - /* This function doesn't support PKCS#11 bypass. We fallback on the - * non-constant time version. */ - goto fallback; - } - - if (spec->mac_def->mac == mac_null) { - *outLen = 0; - return SECSuccess; - } - - macType = CKM_NSS_HMAC_CONSTANT_TIME; - if (spec->version <= SSL_LIBRARY_VERSION_3_0) { - macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME; - } - - params.macAlg = spec->mac_def->mmech; - params.ulBodyTotalLen = originalLen; - params.pHeader = (unsigned char *)header; /* const cast */ - params.ulHeaderLen = headerLen; - - param.data = (unsigned char *)¶ms; - param.len = sizeof(params); - param.type = 0; - - inputItem.data = (unsigned char *)input; - inputItem.len = inputLen; - inputItem.type = 0; - - outputItem.data = outbuf; - outputItem.len = *outLen; - outputItem.type = 0; - - key = spec->server.write_mac_key; - if (!useServerMacKey) { - key = spec->client.write_mac_key; - } - - rv = PK11_SignWithSymKey(key, macType, ¶m, &outputItem, &inputItem); - if (rv != SECSuccess) { - if (PORT_GetError() == SEC_ERROR_INVALID_ALGORITHM) { - goto fallback; - } - - *outLen = 0; - rv = SECFailure; - ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); - return rv; - } - - PORT_Assert(outputItem.len == (unsigned)spec->mac_size); - *outLen = outputItem.len; - - return rv; - -fallback: - /* ssl3_ComputeRecordMAC expects the MAC to have been removed from the - * length already. */ - inputLen -= spec->mac_size; - return ssl3_ComputeRecordMAC(spec, useServerMacKey, header, headerLen, - input, inputLen, outbuf, outLen); -} - -static PRBool -ssl3_ClientAuthTokenPresent(sslSessionID *sid) -{ - PK11SlotInfo *slot = NULL; - PRBool isPresent = PR_TRUE; - - /* we only care if we are doing client auth */ - if (!sid || !sid->u.ssl3.clAuthValid) { - return PR_TRUE; - } - - /* get the slot */ - slot = SECMOD_LookupSlot(sid->u.ssl3.clAuthModuleID, - sid->u.ssl3.clAuthSlotID); - if (slot == NULL || - !PK11_IsPresent(slot) || - sid->u.ssl3.clAuthSeries != PK11_GetSlotSeries(slot) || - sid->u.ssl3.clAuthSlotID != PK11_GetSlotID(slot) || - sid->u.ssl3.clAuthModuleID != PK11_GetModuleID(slot) || - (PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, NULL))) { - isPresent = PR_FALSE; - } - if (slot) { - PK11_FreeSlot(slot); - } - return isPresent; -} - -/* Caller must hold the spec read lock. */ -SECStatus -ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, - PRBool isServer, - PRBool isDTLS, - PRBool capRecordVersion, - SSL3ContentType type, - const SSL3Opaque *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf) -{ - const ssl3BulkCipherDef *cipher_def; - SECStatus rv; - PRUint32 macLen = 0; - PRUint32 fragLen; - PRUint32 p1Len, p2Len, oddLen = 0; - PRUint16 headerLen; - unsigned int ivLen = 0; - int cipherBytes = 0; - unsigned char pseudoHeader[13]; - unsigned int pseudoHeaderLen; - - cipher_def = cwSpec->cipher_def; - headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH; - - if (cipher_def->type == type_block && - cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { - /* Prepend the per-record explicit IV using technique 2b from - * RFC 4346 section 6.2.3.2: The IV is a cryptographically - * strong random number XORed with the CBC residue from the previous - * record. - */ - ivLen = cipher_def->iv_size; - if (ivLen > wrBuf->space - headerLen) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - rv = PK11_GenerateRandom(wrBuf->buf + headerLen, ivLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); - return rv; - } - rv = cwSpec->encode(cwSpec->encodeContext, - wrBuf->buf + headerLen, - &cipherBytes, /* output and actual outLen */ - ivLen, /* max outlen */ - wrBuf->buf + headerLen, - ivLen); /* input and inputLen*/ - if (rv != SECSuccess || cipherBytes != ivLen) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - return SECFailure; - } - } - - if (cwSpec->compressor) { - int outlen; - rv = cwSpec->compressor( - cwSpec->compressContext, - wrBuf->buf + headerLen + ivLen, &outlen, - wrBuf->space - headerLen - ivLen, pIn, contentLen); - if (rv != SECSuccess) - return rv; - pIn = wrBuf->buf + headerLen + ivLen; - contentLen = outlen; - } - - pseudoHeaderLen = ssl3_BuildRecordPseudoHeader( - pseudoHeader, cwSpec->write_seq_num, type, - cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version, - isDTLS, contentLen); - PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader)); - if (cipher_def->type == type_aead) { - const int nonceLen = cipher_def->explicit_nonce_size; - const int tagLen = cipher_def->tag_size; - - if (headerLen + nonceLen + contentLen + tagLen > wrBuf->space) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - cipherBytes = contentLen; - rv = cwSpec->aead( - isServer ? &cwSpec->server : &cwSpec->client, - PR_FALSE, /* do encrypt */ - wrBuf->buf + headerLen, /* output */ - &cipherBytes, /* out len */ - wrBuf->space - headerLen, /* max out */ - pIn, contentLen, /* input */ - pseudoHeader, pseudoHeaderLen); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - return SECFailure; - } - } else { - /* - * Add the MAC - */ - rv = ssl3_ComputeRecordMAC(cwSpec, isServer, - pseudoHeader, pseudoHeaderLen, pIn, contentLen, - wrBuf->buf + headerLen + ivLen + contentLen, - &macLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); - return SECFailure; - } - p1Len = contentLen; - p2Len = macLen; - fragLen = contentLen + macLen; /* needs to be encrypted */ - PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024); - - /* - * Pad the text (if we're doing a block cipher) - * then Encrypt it - */ - if (cipher_def->type == type_block) { - unsigned char *pBuf; - int padding_length; - int i; - - oddLen = contentLen % cipher_def->block_size; - /* Assume blockSize is a power of two */ - padding_length = cipher_def->block_size - 1 - ((fragLen) & (cipher_def->block_size - 1)); - fragLen += padding_length + 1; - PORT_Assert((fragLen % cipher_def->block_size) == 0); - - /* Pad according to TLS rules (also acceptable to SSL3). */ - pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1]; - for (i = padding_length + 1; i > 0; --i) { - *pBuf-- = padding_length; - } - /* now, if contentLen is not a multiple of block size, fix it */ - p2Len = fragLen - p1Len; - } - if (p1Len < 256) { - oddLen = p1Len; - p1Len = 0; - } else { - p1Len -= oddLen; - } - if (oddLen) { - p2Len += oddLen; - PORT_Assert((cipher_def->block_size < 2) || - (p2Len % cipher_def->block_size) == 0); - memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, - oddLen); - } - if (p1Len > 0) { - int cipherBytesPart1 = -1; - rv = cwSpec->encode(cwSpec->encodeContext, - wrBuf->buf + headerLen + ivLen, /* output */ - &cipherBytesPart1, /* actual outlen */ - p1Len, /* max outlen */ - pIn, - p1Len); /* input, and inputlen */ - PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int)p1Len); - if (rv != SECSuccess || cipherBytesPart1 != (int)p1Len) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - return SECFailure; - } - cipherBytes += cipherBytesPart1; - } - if (p2Len > 0) { - int cipherBytesPart2 = -1; - rv = cwSpec->encode(cwSpec->encodeContext, - wrBuf->buf + headerLen + ivLen + p1Len, - &cipherBytesPart2, /* output and actual outLen */ - p2Len, /* max outlen */ - wrBuf->buf + headerLen + ivLen + p1Len, - p2Len); /* input and inputLen*/ - PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int)p2Len); - if (rv != SECSuccess || cipherBytesPart2 != (int)p2Len) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - return SECFailure; - } - cipherBytes += cipherBytesPart2; - } - } - - PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); - - wrBuf->len = cipherBytes + headerLen; - wrBuf->buf[0] = type; - if (isDTLS) { - SSL3ProtocolVersion version; - - version = dtls_TLSVersionToDTLSVersion(cwSpec->version); - wrBuf->buf[1] = MSB(version); - wrBuf->buf[2] = LSB(version); - wrBuf->buf[3] = (unsigned char)(cwSpec->write_seq_num.high >> 24); - wrBuf->buf[4] = (unsigned char)(cwSpec->write_seq_num.high >> 16); - wrBuf->buf[5] = (unsigned char)(cwSpec->write_seq_num.high >> 8); - wrBuf->buf[6] = (unsigned char)(cwSpec->write_seq_num.high >> 0); - wrBuf->buf[7] = (unsigned char)(cwSpec->write_seq_num.low >> 24); - wrBuf->buf[8] = (unsigned char)(cwSpec->write_seq_num.low >> 16); - wrBuf->buf[9] = (unsigned char)(cwSpec->write_seq_num.low >> 8); - wrBuf->buf[10] = (unsigned char)(cwSpec->write_seq_num.low >> 0); - wrBuf->buf[11] = MSB(cipherBytes); - wrBuf->buf[12] = LSB(cipherBytes); - } else { - SSL3ProtocolVersion version = cwSpec->version; - - if (capRecordVersion || version >= SSL_LIBRARY_VERSION_TLS_1_3) { - version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version); - } - - wrBuf->buf[1] = MSB(version); - wrBuf->buf[2] = LSB(version); - wrBuf->buf[3] = MSB(cipherBytes); - wrBuf->buf[4] = LSB(cipherBytes); - } - - ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); - - return SECSuccess; -} - -/* Process the plain text before sending it. - * Returns the number of bytes of plaintext that were successfully sent - * plus the number of bytes of plaintext that were copied into the - * output (write) buffer. - * Returns SECFailure on a hard IO error, memory error, or crypto error. - * Does NOT return SECWouldBlock. - * - * Notes on the use of the private ssl flags: - * (no private SSL flags) - * Attempt to make and send SSL records for all plaintext - * If non-blocking and a send gets WOULD_BLOCK, - * or if the pending (ciphertext) buffer is not empty, - * then buffer remaining bytes of ciphertext into pending buf, - * and continue to do that for all succssive records until all - * bytes are used. - * ssl_SEND_FLAG_FORCE_INTO_BUFFER - * As above, except this suppresses all write attempts, and forces - * all ciphertext into the pending ciphertext buffer. - * ssl_SEND_FLAG_USE_EPOCH (for DTLS) - * Forces the use of the provided epoch - * ssl_SEND_FLAG_CAP_RECORD_VERSION - * Caps the record layer version number of TLS ClientHello to { 3, 1 } - * (TLS 1.0). Some TLS 1.0 servers (which seem to use F5 BIG-IP) ignore - * ClientHello.client_version and use the record layer version number - * (TLSPlaintext.version) instead when negotiating protocol versions. In - * addition, if the record layer version number of ClientHello is { 3, 2 } - * (TLS 1.1) or higher, these servers reset the TCP connections. Lastly, - * some F5 BIG-IP servers hang if a record containing a ClientHello has a - * version greater than { 3, 1 } and a length greater than 255. Set this - * flag to work around such servers. - */ -PRInt32 -ssl3_SendRecord(sslSocket *ss, - DTLSEpoch epoch, /* DTLS only */ - SSL3ContentType type, - const SSL3Opaque *pIn, /* input buffer */ - PRInt32 nIn, /* bytes of input */ - PRInt32 flags) -{ - sslBuffer *wrBuf = &ss->sec.writeBuf; - SECStatus rv; - PRInt32 totalSent = 0; - PRBool capRecordVersion; - - SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", - SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), - nIn)); - PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - if (ss->ssl3.fatalAlertSent) { - SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent", - SSL_GETPID(), ss->fd)); - return SECFailure; - } - - capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0); - - if (capRecordVersion) { - /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the - * TLS initial ClientHello. */ - PORT_Assert(!IS_DTLS(ss)); - PORT_Assert(!ss->firstHsDone); - PORT_Assert(type == content_handshake); - PORT_Assert(ss->ssl3.hs.ws == wait_server_hello); - } - - if (ss->ssl3.initialized == PR_FALSE) { - /* This can happen on a server if the very first incoming record - ** looks like a defective ssl3 record (e.g. too long), and we're - ** trying to send an alert. - */ - PR_ASSERT(type == content_alert); - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - return SECFailure; /* ssl3_InitState has set the error code. */ - } - } - - /* check for Token Presence */ - if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) { - PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); - return SECFailure; - } - - while (nIn > 0) { - PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH); - unsigned int spaceNeeded; - unsigned int numRecords; - - ssl_GetSpecReadLock(ss); /********************************/ - - if (nIn > 1 && ss->opt.cbcRandomIV && - ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_1 && - type == content_application_data && - ss->ssl3.cwSpec->cipher_def->type == type_block /* CBC mode */) { - /* We will split the first byte of the record into its own record, - * as explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h - */ - numRecords = 2; - } else { - numRecords = 1; - } - - spaceNeeded = contentLen + (numRecords * SSL3_BUFFER_FUDGE); - if (ss->ssl3.cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1 && - ss->ssl3.cwSpec->cipher_def->type == type_block) { - spaceNeeded += ss->ssl3.cwSpec->cipher_def->iv_size; - } - if (spaceNeeded > wrBuf->space) { - rv = sslBuffer_Grow(wrBuf, spaceNeeded); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, spaceNeeded)); - goto spec_locked_loser; /* sslBuffer_Grow set error code. */ - } - } - - if (numRecords == 2) { - sslBuffer secondRecord; - rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, - ss->sec.isServer, IS_DTLS(ss), - capRecordVersion, type, pIn, - 1, wrBuf); - if (rv != SECSuccess) - goto spec_locked_loser; - - PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:", - wrBuf->buf, wrBuf->len)); - - secondRecord.buf = wrBuf->buf + wrBuf->len; - secondRecord.len = 0; - secondRecord.space = wrBuf->space - wrBuf->len; - - rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, - ss->sec.isServer, IS_DTLS(ss), - capRecordVersion, type, - pIn + 1, - contentLen - 1, - &secondRecord); - if (rv == SECSuccess) { - PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:", - secondRecord.buf, secondRecord.len)); - wrBuf->len += secondRecord.len; - } - } else { - if (!IS_DTLS(ss)) { - if (ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, - ss->sec.isServer, - PR_FALSE, - capRecordVersion, - type, pIn, - contentLen, wrBuf); - } else { - rv = tls13_ProtectRecord(ss, type, pIn, - contentLen, wrBuf); - } - } else { - /* TLS <= 1.2 and TLS 1.3 cases are both handled in - * dtls_CompressMACEncryptRecord. */ - rv = dtls_CompressMACEncryptRecord(ss, epoch, - !!(flags & ssl_SEND_FLAG_USE_EPOCH), - type, pIn, - contentLen, wrBuf); - } - - if (rv == SECSuccess) { - PRINT_BUF(50, (ss, "send (encrypted) record data:", - wrBuf->buf, wrBuf->len)); - } - } - - spec_locked_loser: - ssl_ReleaseSpecReadLock(ss); /************************************/ - - if (rv != SECSuccess) - return SECFailure; - - pIn += contentLen; - nIn -= contentLen; - PORT_Assert(nIn >= 0); - - /* If there's still some previously saved ciphertext, - * or the caller doesn't want us to send the data yet, - * then add all our new ciphertext to the amount previously saved. - */ - if ((ss->pendingBuf.len > 0) || - (flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - - rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len); - if (rv != SECSuccess) { - /* presumably a memory error, SEC_ERROR_NO_MEMORY */ - return SECFailure; - } - wrBuf->len = 0; /* All cipher text is saved away. */ - - if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - PRInt32 sent; - ss->handshakeBegun = 1; - sent = ssl_SendSavedWriteData(ss); - if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) { - ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return SECFailure; - } - if (ss->pendingBuf.len) { - flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER; - } - } - } else if (wrBuf->len > 0) { - PRInt32 sent; - ss->handshakeBegun = 1; - sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len, - flags & ~ssl_SEND_FLAG_MASK); - if (sent < 0) { - if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { - ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return SECFailure; - } - /* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */ - sent = 0; - } - wrBuf->len -= sent; - if (wrBuf->len) { - if (IS_DTLS(ss)) { - /* DTLS just says no in this case. No buffering */ - PR_SetError(PR_WOULD_BLOCK_ERROR, 0); - return SECFailure; - } - /* now take all the remaining unsent new ciphertext and - * append it to the buffer of previously unsent ciphertext. - */ - rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len); - if (rv != SECSuccess) { - /* presumably a memory error, SEC_ERROR_NO_MEMORY */ - return SECFailure; - } - } - } - totalSent += contentLen; - } - return totalSent; -} - -#define SSL3_PENDING_HIGH_WATER 1024 - -/* Attempt to send the content of "in" in an SSL application_data record. - * Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess. - */ -int -ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, - PRInt32 len, PRInt32 flags) -{ - PRInt32 totalSent = 0; - PRInt32 discarded = 0; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - /* These flags for internal use only */ - PORT_Assert(!(flags & (ssl_SEND_FLAG_USE_EPOCH | - ssl_SEND_FLAG_NO_RETRANSMIT))); - if (len < 0 || !in) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - - if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER && - !ssl_SocketIsBlocking(ss)) { - PORT_Assert(!ssl_SocketIsBlocking(ss)); - PORT_SetError(PR_WOULD_BLOCK_ERROR); - return SECFailure; - } - - if (ss->appDataBuffered && len) { - PORT_Assert(in[0] == (unsigned char)(ss->appDataBuffered)); - if (in[0] != (unsigned char)(ss->appDataBuffered)) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - in++; - len--; - discarded = 1; - } - while (len > totalSent) { - PRInt32 sent, toSend; - - if (totalSent > 0) { - /* - * The thread yield is intended to give the reader thread a - * chance to get some cycles while the writer thread is in - * the middle of a large application data write. (See - * Bugzilla bug 127740, comment #1.) - */ - ssl_ReleaseXmitBufLock(ss); - PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */ - ssl_GetXmitBufLock(ss); - } - toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); - /* - * Note that the 0 epoch is OK because flags will never require - * its use, as guaranteed by the PORT_Assert above. - */ - sent = ssl3_SendRecord(ss, 0, content_application_data, - in + totalSent, toSend, flags); - if (sent < 0) { - if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) { - PORT_Assert(ss->lastWriteBlocked); - break; - } - return SECFailure; /* error code set by ssl3_SendRecord */ - } - totalSent += sent; - if (ss->pendingBuf.len) { - /* must be a non-blocking socket */ - PORT_Assert(!ssl_SocketIsBlocking(ss)); - PORT_Assert(ss->lastWriteBlocked); - break; - } - } - if (ss->pendingBuf.len) { - /* Must be non-blocking. */ - PORT_Assert(!ssl_SocketIsBlocking(ss)); - if (totalSent > 0) { - ss->appDataBuffered = 0x100 | in[totalSent - 1]; - } - - totalSent = totalSent + discarded - 1; - if (totalSent <= 0) { - PORT_SetError(PR_WOULD_BLOCK_ERROR); - totalSent = SECFailure; - } - return totalSent; - } - ss->appDataBuffered = 0; - return totalSent + discarded; -} - -/* Attempt to send buffered handshake messages. - * This function returns SECSuccess or SECFailure, never SECWouldBlock. - * Always set sendBuf.len to 0, even when returning SECFailure. - * - * Depending on whether we are doing DTLS or not, this either calls - * - * - ssl3_FlushHandshakeMessages if non-DTLS - * - dtls_FlushHandshakeMessages if DTLS - * - * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(), - * ssl3_AppendHandshake(), ssl3_SendClientHello(), - * ssl3_SendHelloRequest(), ssl3_SendServerHelloDone(), - * ssl3_SendFinished(), - */ -SECStatus -ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) -{ - if (IS_DTLS(ss)) { - return dtls_FlushHandshakeMessages(ss, flags); - } else { - return ssl3_FlushHandshakeMessages(ss, flags); - } -} - -/* Attempt to send the content of sendBuf buffer in an SSL handshake record. - * This function returns SECSuccess or SECFailure, never SECWouldBlock. - * Always set sendBuf.len to 0, even when returning SECFailure. - * - * Called from ssl3_FlushHandshake - */ -static SECStatus -ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) -{ - static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER | - ssl_SEND_FLAG_CAP_RECORD_VERSION; - PRInt32 count = -1; - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) - return rv; - - /* only these flags are allowed */ - PORT_Assert(!(flags & ~allowedFlags)); - if ((flags & ~allowedFlags) != 0) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } else { - count = ssl3_SendRecord(ss, 0, content_handshake, ss->sec.ci.sendBuf.buf, - ss->sec.ci.sendBuf.len, flags); - } - if (count < 0) { - int err = PORT_GetError(); - PORT_Assert(err != PR_WOULD_BLOCK_ERROR); - if (err == PR_WOULD_BLOCK_ERROR) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } - rv = SECFailure; - } else if ((unsigned int)count < ss->sec.ci.sendBuf.len) { - /* short write should never happen */ - PORT_Assert((unsigned int)count >= ss->sec.ci.sendBuf.len); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } else { - rv = SECSuccess; - } - - /* Whether we succeeded or failed, toss the old handshake data. */ - ss->sec.ci.sendBuf.len = 0; - return rv; -} - -/* - * Called from ssl3_HandleAlert and from ssl3_HandleCertificate when - * the remote client sends a negative response to our certificate request. - * Returns SECFailure if the application has required client auth. - * SECSuccess otherwise. - */ -static SECStatus -ssl3_HandleNoCertificate(sslSocket *ss) -{ - if (ss->sec.peerCert != NULL) { - if (ss->sec.peerKey != NULL) { - SECKEY_DestroyPublicKey(ss->sec.peerKey); - ss->sec.peerKey = NULL; - } - CERT_DestroyCertificate(ss->sec.peerCert); - ss->sec.peerCert = NULL; - } - ssl3_CleanupPeerCerts(ss); - - /* If the server has required client-auth blindly but doesn't - * actually look at the certificate it won't know that no - * certificate was presented so we shutdown the socket to ensure - * an error. We only do this if we haven't already completed the - * first handshake because if we're redoing the handshake we - * know the server is paying attention to the certificate. - */ - if ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) || - (!ss->firstHsDone && - (ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) { - PRFileDesc *lower; - - if (ss->sec.uncache) - ss->sec.uncache(ss->sec.ci.sid); - SSL3_SendAlert(ss, alert_fatal, bad_certificate); - - lower = ss->fd->lower; -#ifdef _WIN32 - lower->methods->shutdown(lower, PR_SHUTDOWN_SEND); -#else - lower->methods->shutdown(lower, PR_SHUTDOWN_BOTH); -#endif - PORT_SetError(SSL_ERROR_NO_CERTIFICATE); - return SECFailure; - } - return SECSuccess; -} - -/************************************************************************ - * Alerts - */ - -/* -** Acquires both handshake and XmitBuf locks. -** Called from: ssl3_IllegalParameter <- -** ssl3_HandshakeFailure <- -** ssl3_HandleAlert <- ssl3_HandleRecord. -** ssl3_HandleChangeCipherSpecs <- ssl3_HandleRecord -** ssl3_ConsumeHandshakeVariable <- -** ssl3_HandleHelloRequest <- -** ssl3_HandleServerHello <- -** ssl3_HandleServerKeyExchange <- -** ssl3_HandleCertificateRequest <- -** ssl3_HandleServerHelloDone <- -** ssl3_HandleClientHello <- -** ssl3_HandleV2ClientHello <- -** ssl3_HandleCertificateVerify <- -** ssl3_HandleClientKeyExchange <- -** ssl3_HandleCertificate <- -** ssl3_HandleFinished <- -** ssl3_HandleHandshakeMessage <- -** ssl3_HandlePostHelloHandshakeMessage <- -** ssl3_HandleRecord <- -** -*/ -SECStatus -SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) -{ - PRUint8 bytes[2]; - SECStatus rv; - - SSL_TRC(3, ("%d: SSL3[%d]: send alert record, level=%d desc=%d", - SSL_GETPID(), ss->fd, level, desc)); - - bytes[0] = level; - bytes[1] = desc; - - ssl_GetSSL3HandshakeLock(ss); - if (level == alert_fatal) { - if (!ss->opt.noCache && ss->sec.ci.sid && ss->sec.uncache) { - ss->sec.uncache(ss->sec.ci.sid); - } - } - ssl_GetXmitBufLock(ss); - rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (rv == SECSuccess) { - PRInt32 sent; - sent = ssl3_SendRecord(ss, 0, content_alert, bytes, 2, - desc == no_certificate ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0); - rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; - } - if (level == alert_fatal) { - ss->ssl3.fatalAlertSent = PR_TRUE; - } - ssl_ReleaseXmitBufLock(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */ -} - -/* - * Send illegal_parameter alert. Set generic error number. - */ -static SECStatus -ssl3_IllegalParameter(sslSocket *ss) -{ - (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT - : SSL_ERROR_BAD_SERVER); - return SECFailure; -} - -/* - * Send handshake_Failure alert. Set generic error number. - */ -static SECStatus -ssl3_HandshakeFailure(sslSocket *ss) -{ - (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); - PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT - : SSL_ERROR_BAD_SERVER); - return SECFailure; -} - -static void -ssl3_SendAlertForCertError(sslSocket *ss, PRErrorCode errCode) -{ - SSL3AlertDescription desc = bad_certificate; - PRBool isTLS = ss->version >= SSL_LIBRARY_VERSION_3_1_TLS; - - switch (errCode) { - case SEC_ERROR_LIBRARY_FAILURE: - desc = unsupported_certificate; - break; - case SEC_ERROR_EXPIRED_CERTIFICATE: - desc = certificate_expired; - break; - case SEC_ERROR_REVOKED_CERTIFICATE: - desc = certificate_revoked; - break; - case SEC_ERROR_INADEQUATE_KEY_USAGE: - case SEC_ERROR_INADEQUATE_CERT_TYPE: - desc = certificate_unknown; - break; - case SEC_ERROR_UNTRUSTED_CERT: - desc = isTLS ? access_denied : certificate_unknown; - break; - case SEC_ERROR_UNKNOWN_ISSUER: - case SEC_ERROR_UNTRUSTED_ISSUER: - desc = isTLS ? unknown_ca : certificate_unknown; - break; - case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: - desc = isTLS ? unknown_ca : certificate_expired; - break; - - case SEC_ERROR_CERT_NOT_IN_NAME_SPACE: - case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID: - case SEC_ERROR_CA_CERT_INVALID: - case SEC_ERROR_BAD_SIGNATURE: - default: - desc = bad_certificate; - break; - } - SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d", - SSL_GETPID(), ss->fd, errCode)); - - (void)SSL3_SendAlert(ss, alert_fatal, desc); -} - -/* - * Send decode_error alert. Set generic error number. - */ -SECStatus -ssl3_DecodeError(sslSocket *ss) -{ - (void)SSL3_SendAlert(ss, alert_fatal, - ss->version > SSL_LIBRARY_VERSION_3_0 ? decode_error - : illegal_parameter); - PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT - : SSL_ERROR_BAD_SERVER); - return SECFailure; -} - -/* Called from ssl3_HandleRecord. -** Caller must hold both RecvBuf and Handshake locks. -*/ -static SECStatus -ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) -{ - SSL3AlertLevel level; - SSL3AlertDescription desc; - int error; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - SSL_TRC(3, ("%d: SSL3[%d]: handle alert record", SSL_GETPID(), ss->fd)); - - if (buf->len != 2) { - (void)ssl3_DecodeError(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_ALERT); - return SECFailure; - } - level = (SSL3AlertLevel)buf->buf[0]; - desc = (SSL3AlertDescription)buf->buf[1]; - buf->len = 0; - SSL_TRC(5, ("%d: SSL3[%d] received alert, level = %d, description = %d", - SSL_GETPID(), ss->fd, level, desc)); - - switch (desc) { - case close_notify: - ss->recvdCloseNotify = 1; - error = SSL_ERROR_CLOSE_NOTIFY_ALERT; - break; - case unexpected_message: - error = SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT; - break; - case bad_record_mac: - error = SSL_ERROR_BAD_MAC_ALERT; - break; - case decryption_failed_RESERVED: - error = SSL_ERROR_DECRYPTION_FAILED_ALERT; - break; - case record_overflow: - error = SSL_ERROR_RECORD_OVERFLOW_ALERT; - break; - case decompression_failure: - error = SSL_ERROR_DECOMPRESSION_FAILURE_ALERT; - break; - case handshake_failure: - error = SSL_ERROR_HANDSHAKE_FAILURE_ALERT; - break; - case no_certificate: - error = SSL_ERROR_NO_CERTIFICATE; - break; - case bad_certificate: - error = SSL_ERROR_BAD_CERT_ALERT; - break; - case unsupported_certificate: - error = SSL_ERROR_UNSUPPORTED_CERT_ALERT; - break; - case certificate_revoked: - error = SSL_ERROR_REVOKED_CERT_ALERT; - break; - case certificate_expired: - error = SSL_ERROR_EXPIRED_CERT_ALERT; - break; - case certificate_unknown: - error = SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT; - break; - case illegal_parameter: - error = SSL_ERROR_ILLEGAL_PARAMETER_ALERT; - break; - case inappropriate_fallback: - error = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; - break; - - /* All alerts below are TLS only. */ - case unknown_ca: - error = SSL_ERROR_UNKNOWN_CA_ALERT; - break; - case access_denied: - error = SSL_ERROR_ACCESS_DENIED_ALERT; - break; - case decode_error: - error = SSL_ERROR_DECODE_ERROR_ALERT; - break; - case decrypt_error: - error = SSL_ERROR_DECRYPT_ERROR_ALERT; - break; - case export_restriction: - error = SSL_ERROR_EXPORT_RESTRICTION_ALERT; - break; - case protocol_version: - error = SSL_ERROR_PROTOCOL_VERSION_ALERT; - break; - case insufficient_security: - error = SSL_ERROR_INSUFFICIENT_SECURITY_ALERT; - break; - case internal_error: - error = SSL_ERROR_INTERNAL_ERROR_ALERT; - break; - case user_canceled: - error = SSL_ERROR_USER_CANCELED_ALERT; - break; - case no_renegotiation: - error = SSL_ERROR_NO_RENEGOTIATION_ALERT; - break; - - /* Alerts for TLS client hello extensions */ - case missing_extension: - error = SSL_ERROR_MISSING_EXTENSION_ALERT; - break; - case unsupported_extension: - error = SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT; - break; - case certificate_unobtainable: - error = SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT; - break; - case unrecognized_name: - error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; - break; - case bad_certificate_status_response: - error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT; - break; - case bad_certificate_hash_value: - error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT; - break; - default: - error = SSL_ERROR_RX_UNKNOWN_ALERT; - break; - } - if (level == alert_fatal) { - if (!ss->opt.noCache) { - if (ss->sec.uncache) - ss->sec.uncache(ss->sec.ci.sid); - } - if ((ss->ssl3.hs.ws == wait_server_hello) && - (desc == handshake_failure)) { - /* XXX This is a hack. We're assuming that any handshake failure - * XXX on the client hello is a failure to match ciphers. - */ - error = SSL_ERROR_NO_CYPHER_OVERLAP; - } - PORT_SetError(error); - return SECFailure; - } - if ((desc == no_certificate) && (ss->ssl3.hs.ws == wait_client_cert)) { - /* I'm a server. I've requested a client cert. He hasn't got one. */ - SECStatus rv; - - PORT_Assert(ss->sec.isServer); - ss->ssl3.hs.ws = wait_client_key; - rv = ssl3_HandleNoCertificate(ss); - return rv; - } - return SECSuccess; -} - -/* - * Change Cipher Specs - * Called from ssl3_HandleServerHelloDone, - * ssl3_HandleClientHello, - * and ssl3_HandleFinished - * - * Acquires and releases spec write lock, to protect switching the current - * and pending write spec pointers. - */ - -static SECStatus -ssl3_SendChangeCipherSpecs(sslSocket *ss) -{ - PRUint8 change = change_cipher_spec_choice; - ssl3CipherSpec *pwSpec; - SECStatus rv; - PRInt32 sent; - - SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ - } - if (!IS_DTLS(ss)) { - sent = ssl3_SendRecord(ss, 0, content_change_cipher_spec, &change, 1, - ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (sent < 0) { - return (SECStatus)sent; /* error code set by ssl3_SendRecord */ - } - } else { - rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1); - if (rv != SECSuccess) { - return rv; - } - } - - /* swap the pending and current write specs. */ - ssl_GetSpecWriteLock(ss); /**************************************/ - pwSpec = ss->ssl3.pwSpec; - - ss->ssl3.pwSpec = ss->ssl3.cwSpec; - ss->ssl3.cwSpec = pwSpec; - - SSL_TRC(3, ("%d: SSL3[%d] Set Current Write Cipher Suite to Pending", - SSL_GETPID(), ss->fd)); - - /* We need to free up the contexts, keys and certs ! */ - /* If we are really through with the old cipher spec - * (Both the read and write sides have changed) destroy it. - */ - if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - if (!IS_DTLS(ss)) { - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE /*freeSrvName*/); - } else { - /* With DTLS, we need to set a holddown timer in case the final - * message got lost */ - ss->ssl3.hs.rtTimeoutMs = DTLS_FINISHED_TIMER_MS; - dtls_StartTimer(ss, dtls_FinishedTimerCb); - } - } - ssl_ReleaseSpecWriteLock(ss); /**************************************/ - - return SECSuccess; -} - -/* Called from ssl3_HandleRecord. -** Caller must hold both RecvBuf and Handshake locks. - * - * Acquires and releases spec write lock, to protect switching the current - * and pending write spec pointers. -*/ -static SECStatus -ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) -{ - ssl3CipherSpec *prSpec; - SSL3WaitState ws = ss->ssl3.hs.ws; - SSL3ChangeCipherSpecChoice change; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - SSL_TRC(3, ("%d: SSL3[%d]: handle change_cipher_spec record", - SSL_GETPID(), ss->fd)); - - if (ws != wait_change_cipher) { - if (IS_DTLS(ss)) { - /* Ignore this because it's out of order. */ - SSL_TRC(3, ("%d: SSL3[%d]: discard out of order " - "DTLS change_cipher_spec", - SSL_GETPID(), ss->fd)); - buf->len = 0; - return SECSuccess; - } - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER); - return SECFailure; - } - - if (buf->len != 1) { - (void)ssl3_DecodeError(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER); - return SECFailure; - } - change = (SSL3ChangeCipherSpecChoice)buf->buf[0]; - if (change != change_cipher_spec_choice) { - /* illegal_parameter is correct here for both SSL3 and TLS. */ - (void)ssl3_IllegalParameter(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER); - return SECFailure; - } - buf->len = 0; - - /* Swap the pending and current read specs. */ - ssl_GetSpecWriteLock(ss); /*************************************/ - prSpec = ss->ssl3.prSpec; - - ss->ssl3.prSpec = ss->ssl3.crSpec; - ss->ssl3.crSpec = prSpec; - ss->ssl3.hs.ws = wait_finished; - - SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", - SSL_GETPID(), ss->fd)); - - /* If we are really through with the old cipher prSpec - * (Both the read and write sides have changed) destroy it. - */ - if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE /*freeSrvName*/); - } - ssl_ReleaseSpecWriteLock(ss); /*************************************/ - return SECSuccess; -} - -/* This method completes the derivation of the MS from the PMS. -** -** 1. Derive the MS, if possible, else return an error. -** -** 2. Check the version if |pms_version| is non-zero and if wrong, -** return an error. -** -** 3. If |msp| is nonzero, return MS in |*msp|. - -** Called from: -** ssl3_ComputeMasterSecretInt -** tls_ComputeExtendedMasterSecretInt -*/ -static SECStatus -ssl3_ComputeMasterSecretFinish(sslSocket *ss, - CK_MECHANISM_TYPE master_derive, - CK_MECHANISM_TYPE key_derive, - CK_VERSION *pms_version, - SECItem *params, CK_FLAGS keyFlags, - PK11SymKey *pms, PK11SymKey **msp) -{ - PK11SymKey *ms = NULL; - - ms = PK11_DeriveWithFlags(pms, master_derive, - params, key_derive, - CKA_DERIVE, 0, keyFlags); - if (!ms) { - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - - if (pms_version && ss->opt.detectRollBack) { - SSL3ProtocolVersion client_version; - client_version = pms_version->major << 8 | pms_version->minor; - - if (IS_DTLS(ss)) { - client_version = dtls_DTLSVersionToTLSVersion(client_version); - } - - if (client_version != ss->clientHelloVersion) { - /* Destroy MS. Version roll-back detected. */ - PK11_FreeSymKey(ms); - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - } - - if (msp) { - *msp = ms; - } else { - PK11_FreeSymKey(ms); - } - - return SECSuccess; -} - -/* Compute the ordinary (pre draft-ietf-tls-session-hash) master - ** secret and return it in |*msp|. - ** - ** Called from: ssl3_ComputeMasterSecret - */ -static SECStatus -ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms, - PK11SymKey **msp) -{ - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; - unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random; - unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random; - PRBool isTLS = (PRBool)(kea_def->tls_keygen || - (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); - PRBool isTLS12 = - (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - /* - * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH - * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size - * data into a 48-byte value, and does not expect to return the version. - */ - PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) || - (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh)); - CK_MECHANISM_TYPE master_derive; - CK_MECHANISM_TYPE key_derive; - SECItem params; - CK_FLAGS keyFlags; - CK_VERSION pms_version; - CK_VERSION *pms_version_ptr = NULL; - /* master_params may be used as a CK_SSL3_MASTER_KEY_DERIVE_PARAMS */ - CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params; - unsigned int master_params_len; - - if (isTLS12) { - if (isDH) - master_derive = CKM_TLS12_MASTER_KEY_DERIVE_DH; - else - master_derive = CKM_TLS12_MASTER_KEY_DERIVE; - key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE; - keyFlags = CKF_SIGN | CKF_VERIFY; - } else if (isTLS) { - if (isDH) - master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH; - else - master_derive = CKM_TLS_MASTER_KEY_DERIVE; - key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; - keyFlags = CKF_SIGN | CKF_VERIFY; - } else { - if (isDH) - master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH; - else - master_derive = CKM_SSL3_MASTER_KEY_DERIVE; - key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; - keyFlags = 0; - } - - if (!isDH) { - pms_version_ptr = &pms_version; - } - - master_params.pVersion = pms_version_ptr; - master_params.RandomInfo.pClientRandom = cr; - master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - master_params.RandomInfo.pServerRandom = sr; - master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH; - if (isTLS12) { - master_params.prfHashMechanism = CKM_SHA256; - master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS); - } else { - /* prfHashMechanism is not relevant with this PRF */ - master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS); - } - - params.data = (unsigned char *)&master_params; - params.len = master_params_len; - - return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive, - pms_version_ptr, ¶ms, - keyFlags, pms, msp); -} - -/* Compute the draft-ietf-tls-session-hash master -** secret and return it in |*msp|. -** -** Called from: ssl3_ComputeMasterSecret -*/ -static SECStatus -tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms, - PK11SymKey **msp) -{ - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS extended_master_params; - SSL3Hashes hashes; - /* - * Determine whether to use the DH/ECDH or RSA derivation modes. - */ - /* - * TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion - * mode. Bug 1198298 */ - PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) || - (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh)); - CK_MECHANISM_TYPE master_derive; - CK_MECHANISM_TYPE key_derive; - SECItem params; - const CK_FLAGS keyFlags = CKF_SIGN | CKF_VERIFY; - CK_VERSION pms_version; - CK_VERSION *pms_version_ptr = NULL; - SECStatus rv; - - rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0); - if (rv != SECSuccess) { - PORT_Assert(0); /* Should never fail */ - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - - if (isDH) { - master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH; - } else { - master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE; - pms_version_ptr = &pms_version; - } - - if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - /* TLS 1.2 */ - extended_master_params.prfHashMechanism = CKM_SHA256; - key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE; - } else { - /* TLS < 1.2 */ - extended_master_params.prfHashMechanism = CKM_TLS_PRF; - key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; - } - - extended_master_params.pVersion = pms_version_ptr; - extended_master_params.pSessionHash = hashes.u.raw; - extended_master_params.ulSessionHashLen = hashes.len; - - params.data = (unsigned char *)&extended_master_params; - params.len = sizeof extended_master_params; - - return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive, - pms_version_ptr, ¶ms, - keyFlags, pms, msp); -} - -/* Wrapper method to compute the master secret and return it in |*msp|. -** -** Called from ssl3_ComputeMasterSecret -*/ -static SECStatus -ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms, - PK11SymKey **msp) -{ - PORT_Assert(pms != NULL); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) { - return tls_ComputeExtendedMasterSecretInt(ss, pms, msp); - } else { - return ssl3_ComputeMasterSecretInt(ss, pms, msp); - } -} - -/* This method uses PKCS11 to derive the MS from the PMS, where PMS -** is a PKCS11 symkey. We call ssl3_ComputeMasterSecret to do the -** computations and then modify the pwSpec->state as a side effect. -** -** This is used in all cases except the "triple bypass" with RSA key -** exchange. -** -** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec. -*/ -static SECStatus -ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) -{ - SECStatus rv; - PK11SymKey *ms = NULL; - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - if (pms) { - rv = ssl3_ComputeMasterSecret(ss, pms, &ms); - pwSpec->master_secret = ms; - if (rv != SECSuccess) - return rv; - } - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - SECItem *keydata; - /* In hope of doing a "double bypass", - * need to extract the master secret's value from the key object - * and store it raw in the sslSocket struct. - */ - rv = PK11_ExtractKeyValue(pwSpec->master_secret); - if (rv != SECSuccess) { - return rv; - } - /* This returns the address of the secItem inside the key struct, - * not a copy or a reference. So, there's no need to free it. - */ - keydata = PK11_GetKeyData(pwSpec->master_secret); - if (keydata && keydata->len <= sizeof pwSpec->raw_master_secret) { - memcpy(pwSpec->raw_master_secret, keydata->data, keydata->len); - pwSpec->msItem.data = pwSpec->raw_master_secret; - pwSpec->msItem.len = keydata->len; - } else { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - } -#endif - - return SECSuccess; -} - -/* - * Derive encryption and MAC Keys (and IVs) from master secret - * Sets a useful error code when returning SECFailure. - * - * Called only from ssl3_InitPendingCipherSpec(), - * which in turn is called from - * sendRSAClientKeyExchange (for Full handshake) - * sendDHClientKeyExchange (for Full handshake) - * ssl3_HandleClientKeyExchange (for Full handshake) - * ssl3_HandleServerHello (for session restart) - * ssl3_HandleClientHello (for session restart) - * Caller MUST hold the specWriteLock, and SSL3HandshakeLock. - * ssl3_InitPendingCipherSpec does that. - * - */ -static SECStatus -ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss) -{ - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; - unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random; - unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random; - PRBool isTLS = (PRBool)(kea_def->tls_keygen || - (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); - PRBool isTLS12 = - (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - /* following variables used in PKCS11 path */ - const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; - PK11SlotInfo *slot = NULL; - PK11SymKey *symKey = NULL; - void *pwArg = ss->pkcs11PinArg; - int keySize; - CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a - * CK_SSL3_KEY_MAT_PARAMS */ - unsigned int key_material_params_len; - CK_SSL3_KEY_MAT_OUT returnedKeys; - CK_MECHANISM_TYPE key_derive; - CK_MECHANISM_TYPE bulk_mechanism; - SSLCipherAlgorithm calg; - SECItem params; - PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - if (!pwSpec->master_secret) { - PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - /* - * generate the key material - */ - key_material_params.ulMacSizeInBits = pwSpec->mac_size * BPB; - key_material_params.ulKeySizeInBits = cipher_def->secret_key_size * BPB; - key_material_params.ulIVSizeInBits = cipher_def->iv_size * BPB; - if (cipher_def->type == type_block && - pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { - /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */ - key_material_params.ulIVSizeInBits = 0; - memset(pwSpec->client.write_iv, 0, cipher_def->iv_size); - memset(pwSpec->server.write_iv, 0, cipher_def->iv_size); - } - - key_material_params.bIsExport = (CK_BBOOL)(kea_def->is_limited); - - key_material_params.RandomInfo.pClientRandom = cr; - key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - key_material_params.RandomInfo.pServerRandom = sr; - key_material_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH; - key_material_params.pReturnedKeyMaterial = &returnedKeys; - - returnedKeys.pIVClient = pwSpec->client.write_iv; - returnedKeys.pIVServer = pwSpec->server.write_iv; - keySize = cipher_def->key_size; - - if (skipKeysAndIVs) { - keySize = 0; - key_material_params.ulKeySizeInBits = 0; - key_material_params.ulIVSizeInBits = 0; - returnedKeys.pIVClient = NULL; - returnedKeys.pIVServer = NULL; - } - - calg = cipher_def->calg; - bulk_mechanism = ssl3_Alg2Mech(calg); - - if (isTLS12) { - key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE; - key_material_params.prfHashMechanism = CKM_SHA256; - key_material_params_len = sizeof(CK_TLS12_KEY_MAT_PARAMS); - } else if (isTLS) { - key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; - key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS); - } else { - key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; - key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS); - } - - params.data = (unsigned char *)&key_material_params; - params.len = key_material_params_len; - - /* CKM_SSL3_KEY_AND_MAC_DERIVE is defined to set ENCRYPT, DECRYPT, and - * DERIVE by DEFAULT */ - symKey = PK11_Derive(pwSpec->master_secret, key_derive, ¶ms, - bulk_mechanism, CKA_ENCRYPT, keySize); - if (!symKey) { - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - /* we really should use the actual mac'ing mechanism here, but we - * don't because these types are used to map keytype anyway and both - * mac's map to the same keytype. - */ - slot = PK11_GetSlotFromKey(symKey); - - PK11_FreeSlot(slot); /* slot is held until the key is freed */ - pwSpec->client.write_mac_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - CKM_SSL3_SHA1_MAC, returnedKeys.hClientMacSecret, PR_TRUE, pwArg); - if (pwSpec->client.write_mac_key == NULL) { - goto loser; /* loser sets err */ - } - pwSpec->server.write_mac_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - CKM_SSL3_SHA1_MAC, returnedKeys.hServerMacSecret, PR_TRUE, pwArg); - if (pwSpec->server.write_mac_key == NULL) { - goto loser; /* loser sets err */ - } - if (!skipKeysAndIVs) { - pwSpec->client.write_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - bulk_mechanism, returnedKeys.hClientKey, PR_TRUE, pwArg); - if (pwSpec->client.write_key == NULL) { - goto loser; /* loser sets err */ - } - pwSpec->server.write_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - bulk_mechanism, returnedKeys.hServerKey, PR_TRUE, pwArg); - if (pwSpec->server.write_key == NULL) { - goto loser; /* loser sets err */ - } - } - PK11_FreeSymKey(symKey); - return SECSuccess; - -loser: - if (symKey) - PK11_FreeSymKey(symKey); - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; -} - -/* ssl3_InitHandshakeHashes creates handshake hash contexts and hashes in - * buffered messages in ss->ssl3.hs.messages. */ -static SECStatus -ssl3_InitHandshakeHashes(sslSocket *ss) -{ - SSL_TRC(30, ("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown); -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - PORT_Assert(!ss->ssl3.hs.sha_obj && !ss->ssl3.hs.sha_clone); - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - /* If we ever support ciphersuites where the PRF hash isn't SHA-256 - * then this will need to be updated. */ - ss->ssl3.hs.sha_obj = HASH_GetRawHashObject(HASH_AlgSHA256); - if (!ss->ssl3.hs.sha_obj) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - return SECFailure; - } - ss->ssl3.hs.sha_clone = (void (*)(void *, void *))SHA256_Clone; - ss->ssl3.hs.hashType = handshake_hash_single; - ss->ssl3.hs.sha_obj->begin(ss->ssl3.hs.sha_cx); - } else { - ss->ssl3.hs.hashType = handshake_hash_combo; - MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); - SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); - } - } else -#endif - { - PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha); - /* - * note: We should probably lookup an SSL3 slot for these - * handshake hashes in hopes that we wind up with the same slots - * that the master secret will wind up in ... - */ - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - /* If we ever support ciphersuites where the PRF hash isn't SHA-256 - * then this will need to be updated. */ - ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA256); - if (ss->ssl3.hs.sha == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return SECFailure; - } - ss->ssl3.hs.hashType = handshake_hash_single; - - if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - return SECFailure; - } - - /* Create a backup SHA-1 hash for a potential client auth - * signature. - * - * In TLS 1.2, ssl3_ComputeHandshakeHashes always uses the - * handshake hash function (SHA-256). If the server or the client - * does not support SHA-256 as a signature hash, we can either - * maintain a backup SHA-1 handshake hash or buffer all handshake - * messages. - */ - if (!ss->sec.isServer) { - ss->ssl3.hs.backupHash = PK11_CreateDigestContext(SEC_OID_SHA1); - if (ss->ssl3.hs.backupHash == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return SECFailure; - } - - if (PK11_DigestBegin(ss->ssl3.hs.backupHash) != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return SECFailure; - } - } - } else { - /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or - * created successfully. */ - ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_MD5); - if (ss->ssl3.hs.md5 == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return SECFailure; - } - ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA1); - if (ss->ssl3.hs.sha == NULL) { - PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); - ss->ssl3.hs.md5 = NULL; - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return SECFailure; - } - ss->ssl3.hs.hashType = handshake_hash_combo; - - if (PK11_DigestBegin(ss->ssl3.hs.md5) != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return SECFailure; - } - if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return SECFailure; - } - } - } - - if (ss->ssl3.hs.messages.len > 0) { - if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf, - ss->ssl3.hs.messages.len) != - SECSuccess) { - return SECFailure; - } - PORT_Free(ss->ssl3.hs.messages.buf); - ss->ssl3.hs.messages.buf = NULL; - ss->ssl3.hs.messages.len = 0; - ss->ssl3.hs.messages.space = 0; - } - - return SECSuccess; -} - -static SECStatus -ssl3_RestartHandshakeHashes(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - - SSL_TRC(30, ("%d: SSL3[%d]: reset handshake hashes", - SSL_GETPID(), ss->fd)); - ss->ssl3.hs.hashType = handshake_hash_unknown; - ss->ssl3.hs.messages.len = 0; -#ifndef NO_PKCS11_BYPASS - ss->ssl3.hs.sha_obj = NULL; - ss->ssl3.hs.sha_clone = NULL; -#endif - if (ss->ssl3.hs.md5) { - PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); - ss->ssl3.hs.md5 = NULL; - } - if (ss->ssl3.hs.sha) { - PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE); - ss->ssl3.hs.sha = NULL; - } - return rv; -} - -/* - * Handshake messages - */ -/* Called from ssl3_InitHandshakeHashes() -** ssl3_AppendHandshake() -** ssl3_StartHandshakeHash() -** ssl3_HandleV2ClientHello() -** ssl3_HandleHandshakeMessage() -** Caller must hold the ssl3Handshake lock. -*/ -static SECStatus -ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, - unsigned int l) -{ - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - /* We need to buffer the handshake messages until we have established - * which handshake hash function to use. */ - if (ss->ssl3.hs.hashType == handshake_hash_unknown) { - return sslBuffer_Append(&ss->ssl3.hs.messages, b, l); - } - - PRINT_BUF(90, (NULL, "handshake hash input:", b, l)); - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - if (ss->ssl3.hs.hashType == handshake_hash_single) { - ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l); - } else { - MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l); - SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l); - } - return rv; - } -#endif - if (ss->ssl3.hs.hashType == handshake_hash_single) { - rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - return rv; - } - if (ss->ssl3.hs.backupHash) { - rv = PK11_DigestOp(ss->ssl3.hs.backupHash, b, l); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return rv; - } - } - } else { - rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return rv; - } - rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return rv; - } - } - return rv; -} - -/************************************************************************** - * Append Handshake functions. - * All these functions set appropriate error codes. - * Most rely on ssl3_AppendHandshake to set the error code. - **************************************************************************/ -SECStatus -ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes) -{ - unsigned char *src = (unsigned char *)void_src; - int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* protects sendBuf. */ - - if (!bytes) - return SECSuccess; - if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) { - rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH, - PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes))); - if (rv != SECSuccess) - return rv; /* sslBuffer_Grow has set a memory error code. */ - room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; - } - - PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes)); - rv = ssl3_UpdateHandshakeHashes(ss, src, bytes); - if (rv != SECSuccess) - return rv; /* error code set by ssl3_UpdateHandshakeHashes */ - - while (bytes > room) { - if (room > 0) - PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, - room); - ss->sec.ci.sendBuf.len += room; - rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ - } - bytes -= room; - src += room; - room = ss->sec.ci.sendBuf.space; - PORT_Assert(ss->sec.ci.sendBuf.len == 0); - } - PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes); - ss->sec.ci.sendBuf.len += bytes; - return SECSuccess; -} - -SECStatus -ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize) -{ - SECStatus rv; - PRUint8 b[4]; - PRUint8 *p = b; - - PORT_Assert(lenSize <= 4 && lenSize > 0); - if (lenSize < 4 && num >= (1L << (lenSize * 8))) { - PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG); - return SECFailure; - } - - switch (lenSize) { - case 4: - *p++ = (num >> 24) & 0xff; - case 3: - *p++ = (num >> 16) & 0xff; - case 2: - *p++ = (num >> 8) & 0xff; - case 1: - *p = num & 0xff; - } - SSL_TRC(60, ("%d: number:", SSL_GETPID())); - rv = ssl3_AppendHandshake(ss, &b[0], lenSize); - return rv; /* error code set by AppendHandshake, if applicable. */ -} - -SECStatus -ssl3_AppendHandshakeVariable( - sslSocket *ss, const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize) -{ - SECStatus rv; - - PORT_Assert((bytes < (1 << 8) && lenSize == 1) || - (bytes < (1L << 16) && lenSize == 2) || - (bytes < (1L << 24) && lenSize == 3)); - - SSL_TRC(60, ("%d: append variable:", SSL_GETPID())); - rv = ssl3_AppendHandshakeNumber(ss, bytes, lenSize); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - SSL_TRC(60, ("data:")); - rv = ssl3_AppendHandshake(ss, src, bytes); - return rv; /* error code set by AppendHandshake, if applicable. */ -} - -SECStatus -ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) -{ - SECStatus rv; - - /* If we already have a message in place, we need to enqueue it. - * This empties the buffer. This is a convenient place to call - * dtls_StageHandshakeMessage to mark the message boundary. - */ - if (IS_DTLS(ss)) { - rv = dtls_StageHandshakeMessage(ss); - if (rv != SECSuccess) { - return rv; - } - } - - SSL_TRC(30, ("%d: SSL3[%d]: append handshake header: type %s", - SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(t))); - - rv = ssl3_AppendHandshakeNumber(ss, t, 1); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - rv = ssl3_AppendHandshakeNumber(ss, length, 3); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - - if (IS_DTLS(ss)) { - /* Note that we make an unfragmented message here. We fragment in the - * transmission code, if necessary */ - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.sendMessageSeq, 2); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - ss->ssl3.hs.sendMessageSeq++; - - /* 0 is the fragment offset, because it's not fragmented yet */ - rv = ssl3_AppendHandshakeNumber(ss, 0, 3); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - - /* Fragment length -- set to the packet length because not fragmented */ - rv = ssl3_AppendHandshakeNumber(ss, length, 3); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - } - - return rv; /* error code set by AppendHandshake, if applicable. */ -} - -/* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of - * |sigAndHash| to the current handshake message. */ -SECStatus -ssl3_AppendSignatureAndHashAlgorithm( - sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash) -{ - PRUint8 serialized[2]; - - serialized[0] = (PRUint8)sigAndHash->hashAlg; - serialized[1] = (PRUint8)sigAndHash->sigAlg; - - return ssl3_AppendHandshake(ss, serialized, sizeof(serialized)); -} - -/************************************************************************** - * Consume Handshake functions. - * - * All data used in these functions is protected by two locks, - * the RecvBufLock and the SSL3HandshakeLock - **************************************************************************/ - -/* Read up the next "bytes" number of bytes from the (decrypted) input - * stream "b" (which is *length bytes long). Copy them into buffer "v". - * Reduces *length by bytes. Advances *b by bytes. - * - * If this function returns SECFailure, it has already sent an alert, - * and has set a generic error code. The caller should probably - * override the generic error code by setting another. - */ -SECStatus -ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, - PRUint32 *length) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if ((PRUint32)bytes > *length) { - return ssl3_DecodeError(ss); - } - PORT_Memcpy(v, *b, bytes); - PRINT_BUF(60, (ss, "consume bytes:", *b, bytes)); - *b += bytes; - *length -= bytes; - return SECSuccess; -} - -/* Read up the next "bytes" number of bytes from the (decrypted) input - * stream "b" (which is *length bytes long), and interpret them as an - * integer in network byte order. Returns the received value. - * Reduces *length by bytes. Advances *b by bytes. - * - * Returns SECFailure (-1) on failure. - * This value is indistinguishable from the equivalent received value. - * Only positive numbers are to be received this way. - * Thus, the largest value that may be sent this way is 0x7fffffff. - * On error, an alert has been sent, and a generic error code has been set. - */ -PRInt32 -ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, - PRUint32 *length) -{ - PRUint8 *buf = *b; - int i; - PRInt32 num = 0; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(bytes <= sizeof num); - - if ((PRUint32)bytes > *length) { - return ssl3_DecodeError(ss); - } - PRINT_BUF(60, (ss, "consume bytes:", *b, bytes)); - - for (i = 0; i < bytes; i++) - num = (num << 8) + buf[i]; - *b += bytes; - *length -= bytes; - return num; -} - -/* Read in two values from the incoming decrypted byte stream "b", which is - * *length bytes long. The first value is a number whose size is "bytes" - * bytes long. The second value is a byte-string whose size is the value - * of the first number received. The latter byte-string, and its length, - * is returned in the SECItem i. - * - * Returns SECFailure (-1) on failure. - * On error, an alert has been sent, and a generic error code has been set. - * - * RADICAL CHANGE for NSS 3.11. All callers of this function make copies - * of the data returned in the SECItem *i, so making a copy of it here - * is simply wasteful. So, This function now just sets SECItem *i to - * point to the values in the buffer **b. - */ -SECStatus -ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length) -{ - PRInt32 count; - - PORT_Assert(bytes <= 3); - i->len = 0; - i->data = NULL; - i->type = siBuffer; - count = ssl3_ConsumeHandshakeNumber(ss, bytes, b, length); - if (count < 0) { /* Can't test for SECSuccess here. */ - return SECFailure; - } - if (count > 0) { - if ((PRUint32)count > *length) { - return ssl3_DecodeError(ss); - } - i->data = *b; - i->len = count; - *b += count; - *length -= count; - } - return SECSuccess; -} - -/* tlsHashOIDMap contains the mapping between TLS hash identifiers and the - * SECOidTag used internally by NSS. */ -static const struct { - SSLHashType tlsHash; - SECOidTag oid; -} tlsHashOIDMap[] = { - { ssl_hash_sha1, SEC_OID_SHA1 }, - { ssl_hash_sha256, SEC_OID_SHA256 }, - { ssl_hash_sha384, SEC_OID_SHA384 }, - { ssl_hash_sha512, SEC_OID_SHA512 } -}; - -/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value. - * If the hash is not recognised, SEC_OID_UNKNOWN is returned. - * - * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -SECOidTag -ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc) -{ - unsigned int i; - - for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { - if (hashFunc == tlsHashOIDMap[i].tlsHash) { - return tlsHashOIDMap[i].oid; - } - } - return SEC_OID_UNKNOWN; -} - -/* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm - * identifier for a given KeyType. */ -static SECStatus -ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType, SSLSignType *out) -{ - switch (keyType) { - case rsaKey: - *out = ssl_sign_rsa; - return SECSuccess; - case dsaKey: - *out = ssl_sign_dsa; - return SECSuccess; - case ecKey: - *out = ssl_sign_ecdsa; - return SECSuccess; - default: - PORT_SetError(SEC_ERROR_INVALID_KEY); - return SECFailure; - } -} - -/* ssl3_TLSSignatureAlgorithmForCertificate returns the TLS 1.2 signature - * algorithm identifier for the given certificate. */ -static SECStatus -ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert, - SSLSignType *out) -{ - SECKEYPublicKey *key; - KeyType keyType; - - key = CERT_ExtractPublicKey(cert); - if (key == NULL) { - ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - return SECFailure; - } - - keyType = key->keyType; - SECKEY_DestroyPublicKey(key); - return ssl3_TLSSignatureAlgorithmForKeyType(keyType, out); -} - -/* ssl3_CheckSignatureAndHashAlgorithmConsistency checks that the signature - * algorithm identifier in |sigAndHash| is consistent with the public key in - * |cert|. It also checks the hash algorithm against the configured signature - * algorithms. If all the tests pass, SECSuccess is returned. Otherwise, - * PORT_SetError is called and SECFailure is returned. */ -SECStatus -ssl3_CheckSignatureAndHashAlgorithmConsistency( - sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash, - CERTCertificate *cert) -{ - SECStatus rv; - SSLSignType sigAlg; - unsigned int i; - - /* If we're a client, check that the signature algorithm matches the signing - * key type of the cipher suite. */ - if (!ss->sec.isServer && - ss->ssl3.hs.kea_def->signKeyType != sigAndHash->sigAlg) { - PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); - return SECFailure; - } - - /* Verify that the signature algorithm used for the - * signature matches the signing key. */ - rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg); - if (rv != SECSuccess) { - return rv; - } - if (sigAlg != sigAndHash->sigAlg) { - PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); - return SECFailure; - } - - for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) { - const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i]; - if (sigAndHash->sigAlg == alg->sigAlg && - sigAndHash->hashAlg == alg->hashAlg) { - return SECSuccess; - } - } - PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); - return SECFailure; -} - -PRBool -ssl3_IsSupportedSignatureAlgorithm(const SSLSignatureAndHashAlg *alg) -{ - static const SSLHashType supportedHashes[] = { - ssl_hash_sha1, - ssl_hash_sha256, - ssl_hash_sha384, - ssl_hash_sha512 - }; - - static const SSLSignType supportedSigAlgs[] = { - ssl_sign_rsa, -#ifndef NSS_DISABLE_ECC - ssl_sign_ecdsa, -#endif - ssl_sign_dsa - }; - - unsigned int i; - PRBool hashOK = PR_FALSE; - PRBool signOK = PR_FALSE; - - for (i = 0; i < PR_ARRAY_SIZE(supportedHashes); ++i) { - if (alg->hashAlg == supportedHashes[i]) { - hashOK = PR_TRUE; - break; - } - } - - for (i = 0; i < PR_ARRAY_SIZE(supportedSigAlgs); ++i) { - if (alg->sigAlg == supportedSigAlgs[i]) { - signOK = PR_TRUE; - break; - } - } - - return hashOK && signOK; -} - -/* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm - * structure from |b| and puts the resulting value into |out|. |b| and |length| - * are updated accordingly. - * - * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -SECStatus -ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, - SSL3Opaque **b, - PRUint32 *length, - SSLSignatureAndHashAlg *out) -{ - PRUint8 bytes[2]; - SECStatus rv; - - rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length); - if (rv != SECSuccess) { - return rv; - } - - out->hashAlg = (SSLHashType)bytes[0]; - out->sigAlg = (SSLSignType)bytes[1]; - if (!ssl3_IsSupportedSignatureAlgorithm(out)) { - PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); - return SECFailure; - } - return SECSuccess; -} - -/************************************************************************** - * end of Consume Handshake functions. - **************************************************************************/ - -/* Extract the hashes of handshake messages to this point. - * Called from ssl3_SendCertificateVerify - * ssl3_SendFinished - * ssl3_HandleHandshakeMessage - * - * Caller must hold the SSL3HandshakeLock. - * Caller must hold a read or write lock on the Spec R/W lock. - * (There is presently no way to assert on a Read lock.) - */ -SECStatus -ssl3_ComputeHandshakeHashes(sslSocket *ss, - ssl3CipherSpec *spec, /* uses ->master_secret */ - SSL3Hashes *hashes, /* output goes here. */ - PRUint32 sender) -{ - SECStatus rv = SECSuccess; - PRBool isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); - unsigned int outLength; - SSL3Opaque md5_inner[MAX_MAC_LENGTH]; - SSL3Opaque sha_inner[MAX_MAC_LENGTH]; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (ss->ssl3.hs.hashType == handshake_hash_unknown) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - hashes->hashAlg = ssl_hash_none; - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11 && - ss->ssl3.hs.hashType == handshake_hash_single) { - /* compute them without PKCS11 */ - PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; - - ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx); - ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len, - sizeof(hashes->u.raw)); - - PRINT_BUF(60, (NULL, "SHA-256: result", hashes->u.raw, hashes->len)); - - /* If we ever support ciphersuites where the PRF hash isn't SHA-256 - * then this will need to be updated. */ - hashes->hashAlg = ssl_hash_sha256; - rv = SECSuccess; - } else if (ss->opt.bypassPKCS11) { - /* compute them without PKCS11 */ - PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS]; - PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; - -#define md5cx ((MD5Context *)md5_cx) -#define shacx ((SHA1Context *)sha_cx) - - MD5_Clone(md5cx, (MD5Context *)ss->ssl3.hs.md5_cx); - SHA1_Clone(shacx, (SHA1Context *)ss->ssl3.hs.sha_cx); - - if (!isTLS) { - /* compute hashes for SSL3. */ - unsigned char s[4]; - - if (!spec->msItem.data) { - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); - return SECFailure; - } - - s[0] = (unsigned char)(sender >> 24); - s[1] = (unsigned char)(sender >> 16); - s[2] = (unsigned char)(sender >> 8); - s[3] = (unsigned char)sender; - - if (sender != 0) { - MD5_Update(md5cx, s, 4); - PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4)); - } - - PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, - mac_defs[mac_md5].pad_size)); - - MD5_Update(md5cx, spec->msItem.data, spec->msItem.len); - MD5_Update(md5cx, mac_pad_1, mac_defs[mac_md5].pad_size); - MD5_End(md5cx, md5_inner, &outLength, MD5_LENGTH); - - PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength)); - - if (sender != 0) { - SHA1_Update(shacx, s, 4); - PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4)); - } - - PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, - mac_defs[mac_sha].pad_size)); - - SHA1_Update(shacx, spec->msItem.data, spec->msItem.len); - SHA1_Update(shacx, mac_pad_1, mac_defs[mac_sha].pad_size); - SHA1_End(shacx, sha_inner, &outLength, SHA1_LENGTH); - - PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength)); - PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, - mac_defs[mac_md5].pad_size)); - PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); - - MD5_Begin(md5cx); - MD5_Update(md5cx, spec->msItem.data, spec->msItem.len); - MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size); - MD5_Update(md5cx, md5_inner, MD5_LENGTH); - } - MD5_End(md5cx, hashes->u.s.md5, &outLength, MD5_LENGTH); - - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); - - if (!isTLS) { - PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, - mac_defs[mac_sha].pad_size)); - PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); - - SHA1_Begin(shacx); - SHA1_Update(shacx, spec->msItem.data, spec->msItem.len); - SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size); - SHA1_Update(shacx, sha_inner, SHA1_LENGTH); - } - SHA1_End(shacx, hashes->u.s.sha, &outLength, SHA1_LENGTH); - - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); - - hashes->len = MD5_LENGTH + SHA1_LENGTH; - rv = SECSuccess; -#undef md5cx -#undef shacx - } else -#endif - if (ss->ssl3.hs.hashType == handshake_hash_single) { - /* compute hashes with PKCS11 */ - PK11Context *h; - unsigned int stateLen; - unsigned char stackBuf[1024]; - unsigned char *stateBuf = NULL; - - h = ss->ssl3.hs.sha; - stateBuf = PK11_SaveContextAlloc(h, stackBuf, - sizeof(stackBuf), &stateLen); - if (stateBuf == NULL) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - goto tls12_loser; - } - rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len, - sizeof(hashes->u.raw)); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - rv = SECFailure; - goto tls12_loser; - } - /* If we ever support ciphersuites where the PRF hash isn't SHA-256 - * then this will need to be updated. */ - hashes->hashAlg = ssl_hash_sha256; - rv = SECSuccess; - - tls12_loser: - if (stateBuf) { - if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); - rv = SECFailure; - } - if (stateBuf != stackBuf) { - PORT_ZFree(stateBuf, stateLen); - } - } - } else { - /* compute hashes with PKCS11 */ - PK11Context *md5; - PK11Context *sha = NULL; - unsigned char *md5StateBuf = NULL; - unsigned char *shaStateBuf = NULL; - unsigned int md5StateLen, shaStateLen; - unsigned char md5StackBuf[256]; - unsigned char shaStackBuf[512]; - - md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf, - sizeof md5StackBuf, &md5StateLen); - if (md5StateBuf == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - goto loser; - } - md5 = ss->ssl3.hs.md5; - - shaStateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.sha, shaStackBuf, - sizeof shaStackBuf, &shaStateLen); - if (shaStateBuf == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; - } - sha = ss->ssl3.hs.sha; - - if (!isTLS) { - /* compute hashes for SSL3. */ - unsigned char s[4]; - - if (!spec->master_secret) { - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); - rv = SECFailure; - goto loser; - } - - s[0] = (unsigned char)(sender >> 24); - s[1] = (unsigned char)(sender >> 16); - s[2] = (unsigned char)(sender >> 8); - s[3] = (unsigned char)sender; - - if (sender != 0) { - rv |= PK11_DigestOp(md5, s, 4); - PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4)); - } - - PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, - mac_defs[mac_md5].pad_size)); - - rv |= PK11_DigestKey(md5, spec->master_secret); - rv |= PK11_DigestOp(md5, mac_pad_1, mac_defs[mac_md5].pad_size); - rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } - - PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength)); - - if (sender != 0) { - rv |= PK11_DigestOp(sha, s, 4); - PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4)); - } - - PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, - mac_defs[mac_sha].pad_size)); - - rv |= PK11_DigestKey(sha, spec->master_secret); - rv |= PK11_DigestOp(sha, mac_pad_1, mac_defs[mac_sha].pad_size); - rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } - - PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength)); - - PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, - mac_defs[mac_md5].pad_size)); - PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); - - rv |= PK11_DigestBegin(md5); - rv |= PK11_DigestKey(md5, spec->master_secret); - rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); - rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); - } - rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } - - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); - - if (!isTLS) { - PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, - mac_defs[mac_sha].pad_size)); - PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); - - rv |= PK11_DigestBegin(sha); - rv |= PK11_DigestKey(sha, spec->master_secret); - rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); - rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); - } - rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } - - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); - - hashes->len = MD5_LENGTH + SHA1_LENGTH; - rv = SECSuccess; - - loser: - if (md5StateBuf) { - if (PK11_RestoreContext(ss->ssl3.hs.md5, md5StateBuf, md5StateLen) != - SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - } - if (md5StateBuf != md5StackBuf) { - PORT_ZFree(md5StateBuf, md5StateLen); - } - } - if (shaStateBuf) { - if (PK11_RestoreContext(ss->ssl3.hs.sha, shaStateBuf, shaStateLen) != - SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - } - if (shaStateBuf != shaStackBuf) { - PORT_ZFree(shaStateBuf, shaStateLen); - } - } - } - return rv; -} - -static SECStatus -ssl3_ComputeBackupHandshakeHashes(sslSocket *ss, - SSL3Hashes *hashes) /* output goes here. */ -{ - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(!ss->sec.isServer); - PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single); - - rv = PK11_DigestFinal(ss->ssl3.hs.backupHash, hashes->u.raw, &hashes->len, - sizeof(hashes->u.raw)); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } - hashes->hashAlg = ssl_hash_sha1; - -loser: - PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE); - ss->ssl3.hs.backupHash = NULL; - return rv; -} - -/* - * SSL 2 based implementations pass in the initial outbound buffer - * so that the handshake hash can contain the included information. - * - * Called from ssl2_BeginClientHandshake() in sslcon.c - */ -SECStatus -ssl3_StartHandshakeHash(sslSocket *ss, unsigned char *buf, int length) -{ - SECStatus rv; - - ssl_GetSSL3HandshakeLock(ss); /**************************************/ - - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - goto done; /* ssl3_InitState has set the error code. */ - } - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - goto done; - } - - PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH); - PORT_Memcpy( - &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - SSL_CHALLENGE_BYTES], - &ss->sec.ci.clientChallenge, - SSL_CHALLENGE_BYTES); - - rv = ssl3_UpdateHandshakeHashes(ss, buf, length); - /* if it failed, ssl3_UpdateHandshakeHashes has set the error code. */ - -done: - ssl_ReleaseSSL3HandshakeLock(ss); /**************************************/ - return rv; -} - -/************************************************************************** - * end of Handshake Hash functions. - * Begin Send and Handle functions for handshakes. - **************************************************************************/ - -/* Called from ssl3_HandleHelloRequest(), - * ssl3_RedoHandshake() - * ssl2_BeginClientHandshake (when resuming ssl3 session) - * dtls_HandleHelloVerifyRequest(with resending=PR_TRUE) - */ -SECStatus -ssl3_SendClientHello(sslSocket *ss, PRBool resending) -{ - sslSessionID *sid; - ssl3CipherSpec *cwSpec; - SECStatus rv; - int i; - int length; - int num_suites; - int actual_count = 0; - PRBool isTLS = PR_FALSE; - PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; - PRInt32 total_exten_len = 0; - unsigned paddingExtensionLen; - unsigned numCompressionMethods; - PRInt32 flags; - - SSL_TRC(3, ("%d: SSL3[%d]: send client_hello handshake", SSL_GETPID(), - ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - return rv; /* ssl3_InitState has set the error code. */ - } - /* These must be reset every handshake. */ - ss->ssl3.hs.sendingSCSV = PR_FALSE; - ss->ssl3.hs.preliminaryInfo = 0; - PORT_Assert(IS_DTLS(ss) || !resending); - - SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE); - ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE; - - /* We might be starting a session renegotiation in which case we should - * clear previous state. - */ - PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData)); - - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - return rv; - } - - /* - * During a renegotiation, ss->clientHelloVersion will be used again to - * work around a Windows SChannel bug. Ensure that it is still enabled. - */ - if (ss->firstHsDone) { - if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - PORT_SetError(SSL_ERROR_SSL_DISABLED); - return SECFailure; - } - - if (ss->clientHelloVersion < ss->vrange.min || - ss->clientHelloVersion > ss->vrange.max) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return SECFailure; - } - } - - /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup - * handles expired entries and other details. - * XXX If we've been called from ssl2_BeginClientHandshake, then - * this lookup is duplicative and wasteful. - */ - sid = (ss->opt.noCache) ? NULL - : ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url); - - /* We can't resume based on a different token. If the sid exists, - * make sure the token that holds the master secret still exists ... - * If we previously did client-auth, make sure that the token that holds - * the private key still exists, is logged in, hasn't been removed, etc. - */ - if (sid) { - PRBool sidOK = PR_TRUE; - if (sid->u.ssl3.keys.msIsWrapped) { - /* Session key was wrapped, which means it was using PKCS11, */ - PK11SlotInfo *slot = NULL; - if (sid->u.ssl3.masterValid && !ss->opt.bypassPKCS11) { - slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, - sid->u.ssl3.masterSlotID); - } - if (slot == NULL) { - sidOK = PR_FALSE; - } else { - PK11SymKey *wrapKey = NULL; - if (!PK11_IsPresent(slot) || - ((wrapKey = PK11_GetWrapKey(slot, - sid->u.ssl3.masterWrapIndex, - sid->u.ssl3.masterWrapMech, - sid->u.ssl3.masterWrapSeries, - ss->pkcs11PinArg)) == NULL)) { - sidOK = PR_FALSE; - } - if (wrapKey) - PK11_FreeSymKey(wrapKey); - PK11_FreeSlot(slot); - slot = NULL; - } - } - /* If we previously did client-auth, make sure that the token that - ** holds the private key still exists, is logged in, hasn't been - ** removed, etc. - */ - if (sidOK && !ssl3_ClientAuthTokenPresent(sid)) { - sidOK = PR_FALSE; - } - - if (sidOK) { - /* Set ss->version based on the session cache */ - if (ss->firstHsDone) { - /* - * Windows SChannel compares the client_version inside the RSA - * EncryptedPreMasterSecret of a renegotiation with the - * client_version of the initial ClientHello rather than the - * ClientHello in the renegotiation. To work around this bug, we - * continue to use the client_version used in the initial - * ClientHello when renegotiating. - * - * The client_version of the initial ClientHello is still - * available in ss->clientHelloVersion. Ensure that - * sid->version is bounded within - * [ss->vrange.min, ss->clientHelloVersion], otherwise we - * can't use sid. - */ - if (sid->version >= ss->vrange.min && - sid->version <= ss->clientHelloVersion) { - ss->version = ss->clientHelloVersion; - } else { - sidOK = PR_FALSE; - } - } else { - /* - * Check sid->version is OK first. - * Previously, we would cap the version based on sid->version, - * but that prevents negotiation of a higher version if the - * previous session was reduced (e.g., with version fallback) - */ - if (sid->version < ss->vrange.min || - sid->version > ss->vrange.max) { - sidOK = PR_FALSE; - } else { - rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED, - PR_TRUE); - if (rv != SECSuccess) { - return rv; /* error code was set */ - } - } - } - } - - if (!sidOK) { - SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_not_ok); - if (ss->sec.uncache) - (*ss->sec.uncache)(sid); - ssl_FreeSID(sid); - sid = NULL; - } - } - - if (sid) { - requestingResume = PR_TRUE; - SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_hits); - - PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength)); - - ss->ssl3.policy = sid->u.ssl3.policy; - } else { - SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_misses); - - /* - * Windows SChannel compares the client_version inside the RSA - * EncryptedPreMasterSecret of a renegotiation with the - * client_version of the initial ClientHello rather than the - * ClientHello in the renegotiation. To work around this bug, we - * continue to use the client_version used in the initial - * ClientHello when renegotiating. - */ - if (ss->firstHsDone) { - ss->version = ss->clientHelloVersion; - } else { - rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED, - PR_TRUE); - if (rv != SECSuccess) - return rv; /* error code was set */ - } - - sid = ssl3_NewSessionID(ss, PR_FALSE); - if (!sid) { - return SECFailure; /* memory error is set */ - } - } - - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - rv = tls13_SetupClientHello(ss); - if (rv != SECSuccess) { - if (sid) { - ssl_FreeSID(sid); - } - return rv; - } - } - - isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); - ssl_GetSpecWriteLock(ss); - cwSpec = ss->ssl3.cwSpec; - if (cwSpec->mac_def->mac == mac_null) { - /* SSL records are not being MACed. */ - cwSpec->version = ss->version; - } - ssl_ReleaseSpecWriteLock(ss); - - if (ss->sec.ci.sid != NULL) { - ssl_FreeSID(ss->sec.ci.sid); /* decrement ref count, free if zero */ - } - ss->sec.ci.sid = sid; - - ss->sec.send = ssl3_SendApplicationData; - - /* shouldn't get here if SSL3 is disabled, but ... */ - if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - PR_NOT_REACHED("No versions of SSL 3.0 or later are enabled"); - PORT_SetError(SSL_ERROR_SSL_DISABLED); - return SECFailure; - } - - /* how many suites does our PKCS11 support (regardless of policy)? */ - num_suites = ssl3_config_match_init(ss); - if (!num_suites) - return SECFailure; /* ssl3_config_match_init has set error code. */ - - /* HACK for SCSV in SSL 3.0. On initial handshake, prepend SCSV, - * only if TLS is disabled. - */ - if (!ss->firstHsDone && !isTLS) { - /* Must set this before calling Hello Extension Senders, - * to suppress sending of empty RI extension. - */ - ss->ssl3.hs.sendingSCSV = PR_TRUE; - } - - /* When we attempt session resumption (only), we must lock the sid to - * prevent races with other resumption connections that receive a - * NewSessionTicket that will cause the ticket in the sid to be replaced. - * Once we've copied the session ticket into our ClientHello message, it - * is OK for the ticket to change, so we just need to make sure we hold - * the lock across the calls to ssl3_CallHelloExtensionSenders. - */ - if (sid->u.ssl3.lock) { - PR_RWLock_Rlock(sid->u.ssl3.lock); - } - - if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) { - PRUint32 maxBytes = 65535; /* 2^16 - 1 */ - PRInt32 extLen; - - extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, NULL); - if (extLen < 0) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; - } - total_exten_len += extLen; - - if (total_exten_len > 0) - total_exten_len += 2; - } - -#ifndef NSS_DISABLE_ECC - if (!total_exten_len || !isTLS) { - /* not sending the elliptic_curves and ec_point_formats extensions */ - ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */ - } -#endif /* NSS_DISABLE_ECC */ - - if (IS_DTLS(ss)) { - ssl3_DisableNonDTLSSuites(ss); - } - - /* how many suites are permitted by policy and user preference? */ - num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); - if (!num_suites) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; /* count_cipher_suites has set error code. */ - } - - fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume || - ss->version < sid->version); - /* make room for SCSV */ - if (ss->ssl3.hs.sendingSCSV) { - ++num_suites; - } - if (fallbackSCSV) { - ++num_suites; - } - - /* count compression methods */ - numCompressionMethods = 0; - for (i = 0; i < compressionMethodsCount; i++) { - if (compressionEnabled(ss, compressions[i])) - numCompressionMethods++; - } - - length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + - 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength) + - 2 + num_suites * sizeof(ssl3CipherSuite) + - 1 + numCompressionMethods + total_exten_len; - if (IS_DTLS(ss)) { - length += 1 + ss->ssl3.hs.cookieLen; - } - - /* A padding extension may be included to ensure that the record containing - * the ClientHello doesn't have a length between 256 and 511 bytes - * (inclusive). Initial, ClientHello records with such lengths trigger bugs - * in F5 devices. - * - * This is not done for DTLS nor for renegotiation. */ - if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone) { - paddingExtensionLen = ssl3_CalculatePaddingExtensionLength(length); - total_exten_len += paddingExtensionLen; - length += paddingExtensionLen; - } else { - paddingExtensionLen = 0; - } - - rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - - if (ss->firstHsDone) { - /* The client hello version must stay unchanged to work around - * the Windows SChannel bug described above. */ - PORT_Assert(ss->version == ss->clientHelloVersion); - } - ss->clientHelloVersion = ss->version; - if (IS_DTLS(ss)) { - PRUint16 version; - - version = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion); - rv = ssl3_AppendHandshakeNumber(ss, version, 2); - } else { - rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2); - } - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - - if (!resending) { /* Don't re-generate if we are in DTLS re-sending mode */ - rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by GetNewRandom. */ - } - } - rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random, - SSL3_RANDOM_LENGTH); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - - if (sid) - rv = ssl3_AppendHandshakeVariable( - ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1); - else - rv = ssl3_AppendHandshakeNumber(ss, 0, 1); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - - if (IS_DTLS(ss)) { - rv = ssl3_AppendHandshakeVariable( - ss, ss->ssl3.hs.cookie, ss->ssl3.hs.cookieLen, 1); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - } - - rv = ssl3_AppendHandshakeNumber(ss, num_suites * sizeof(ssl3CipherSuite), 2); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - - if (ss->ssl3.hs.sendingSCSV) { - /* Add the actual SCSV */ - rv = ssl3_AppendHandshakeNumber(ss, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, - sizeof(ssl3CipherSuite)); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - actual_count++; - } - if (fallbackSCSV) { - rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, - sizeof(ssl3CipherSuite)); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - actual_count++; - } - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange, ss)) { - actual_count++; - if (actual_count > num_suites) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - /* set error card removal/insertion error */ - PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); - return SECFailure; - } - rv = ssl3_AppendHandshakeNumber(ss, suite->cipher_suite, - sizeof(ssl3CipherSuite)); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - } - } - - /* if cards were removed or inserted between count_cipher_suites and - * generating our list, detect the error here rather than send it off to - * the server.. */ - if (actual_count != num_suites) { - /* Card removal/insertion error */ - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); - return SECFailure; - } - - rv = ssl3_AppendHandshakeNumber(ss, numCompressionMethods, 1); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - for (i = 0; i < compressionMethodsCount; i++) { - if (!compressionEnabled(ss, compressions[i])) - continue; - rv = ssl3_AppendHandshakeNumber(ss, compressions[i], 1); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } - } - - if (total_exten_len) { - PRUint32 maxBytes = total_exten_len - 2; - PRInt32 extLen; - - rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by AppendHandshake. */ - } - - extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL); - if (extLen < 0) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; - } - maxBytes -= extLen; - - extLen = ssl3_AppendPaddingExtension(ss, paddingExtensionLen, maxBytes); - if (extLen < 0) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; - } - maxBytes -= extLen; - - PORT_Assert(!maxBytes); - } - - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - - if (ss->xtnData.sentSessionTicketInClientHello) { - SSL_AtomicIncrementLong(&ssl3stats.sch_sid_stateless_resumes); - } - - if (ss->ssl3.hs.sendingSCSV) { - /* Since we sent the SCSV, pretend we sent empty RI extension. */ - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_renegotiation_info_xtn; - } - - flags = 0; - if (!ss->firstHsDone && !IS_DTLS(ss)) { - flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION; - } - rv = ssl3_FlushHandshake(ss, flags); - if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ - } - - ss->ssl3.hs.ws = wait_server_hello; - return rv; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a - * complete ssl3 Hello Request. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleHelloRequest(sslSocket *ss) -{ - sslSessionID *sid = ss->sec.ci.sid; - SECStatus rv; - - SSL_TRC(3, ("%d: SSL3[%d]: handle hello_request handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - - if (ss->ssl3.hs.ws == wait_server_hello) - return SECSuccess; - if (ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST); - return SECFailure; - } - if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) { - (void)SSL3_SendAlert(ss, alert_warning, no_renegotiation); - PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); - return SECFailure; - } - - if (sid) { - if (ss->sec.uncache) - ss->sec.uncache(sid); - ssl_FreeSID(sid); - ss->sec.ci.sid = NULL; - } - - if (IS_DTLS(ss)) { - dtls_RehandshakeCleanup(ss); - } - - ssl_GetXmitBufLock(ss); - rv = ssl3_SendClientHello(ss, PR_FALSE); - ssl_ReleaseXmitBufLock(ss); - - return rv; -} - -#define UNKNOWN_WRAP_MECHANISM 0x7fffffff - -static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { - CKM_DES3_ECB, - CKM_CAST5_ECB, - CKM_DES_ECB, - CKM_KEY_WRAP_LYNKS, - CKM_IDEA_ECB, - CKM_CAST3_ECB, - CKM_CAST_ECB, - CKM_RC5_ECB, - CKM_RC2_ECB, - CKM_CDMF_ECB, - CKM_SKIPJACK_WRAP, - CKM_SKIPJACK_CBC64, - CKM_AES_ECB, - CKM_CAMELLIA_ECB, - CKM_SEED_ECB, - UNKNOWN_WRAP_MECHANISM -}; - -static int -ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech) -{ - const CK_MECHANISM_TYPE *pMech = wrapMechanismList; - - while (mech != *pMech && *pMech != UNKNOWN_WRAP_MECHANISM) { - ++pMech; - } - return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1 - : (pMech - wrapMechanismList); -} - -static PK11SymKey * -ssl_UnwrapSymWrappingKey( - SSLWrappedSymWrappingKey *pWswk, - SECKEYPrivateKey *svrPrivKey, - SSL3KEAType exchKeyType, - CK_MECHANISM_TYPE masterWrapMech, - void *pwArg) -{ - PK11SymKey *unwrappedWrappingKey = NULL; - SECItem wrappedKey; -#ifndef NSS_DISABLE_ECC - PK11SymKey *Ks; - SECKEYPublicKey pubWrapKey; - ECCWrappedKeyInfo *ecWrapped; -#endif /* NSS_DISABLE_ECC */ - - /* found the wrapping key on disk. */ - PORT_Assert(pWswk->symWrapMechanism == masterWrapMech); - PORT_Assert(pWswk->exchKeyType == exchKeyType); - if (pWswk->symWrapMechanism != masterWrapMech || - pWswk->exchKeyType != exchKeyType) { - goto loser; - } - wrappedKey.type = siBuffer; - wrappedKey.data = pWswk->wrappedSymmetricWrappingkey; - wrappedKey.len = pWswk->wrappedSymKeyLen; - PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey); - - switch (exchKeyType) { - - case kt_rsa: - unwrappedWrappingKey = - PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, - masterWrapMech, CKA_UNWRAP, 0); - break; - -#ifndef NSS_DISABLE_ECC - case kt_ecdh: - /* - * For kt_ecdh, we first create an EC public key based on - * data stored with the wrappedSymmetricWrappingkey. Next, - * we do an ECDH computation involving this public key and - * the SSL server's (long-term) EC private key. The resulting - * shared secret is treated the same way as Fortezza's Ks, i.e., - * it is used to recover the symmetric wrapping key. - * - * The data in wrappedSymmetricWrappingkey is laid out as defined - * in the ECCWrappedKeyInfo structure. - */ - ecWrapped = (ECCWrappedKeyInfo *)pWswk->wrappedSymmetricWrappingkey; - - PORT_Assert(ecWrapped->encodedParamLen + ecWrapped->pubValueLen + - ecWrapped->wrappedKeyLen <= MAX_EC_WRAPPED_KEY_BUFLEN); - - if (ecWrapped->encodedParamLen + ecWrapped->pubValueLen + - ecWrapped->wrappedKeyLen > MAX_EC_WRAPPED_KEY_BUFLEN) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - goto loser; - } - - pubWrapKey.keyType = ecKey; - pubWrapKey.u.ec.size = ecWrapped->size; - pubWrapKey.u.ec.DEREncodedParams.len = ecWrapped->encodedParamLen; - pubWrapKey.u.ec.DEREncodedParams.data = ecWrapped->var; - pubWrapKey.u.ec.publicValue.len = ecWrapped->pubValueLen; - pubWrapKey.u.ec.publicValue.data = ecWrapped->var + - ecWrapped->encodedParamLen; - - wrappedKey.len = ecWrapped->wrappedKeyLen; - wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen + - ecWrapped->pubValueLen; - - /* Derive Ks using ECDH */ - Ks = PK11_PubDeriveWithKDF(svrPrivKey, &pubWrapKey, PR_FALSE, NULL, - NULL, CKM_ECDH1_DERIVE, masterWrapMech, - CKA_DERIVE, 0, CKD_NULL, NULL, NULL); - if (Ks == NULL) { - goto loser; - } - - /* Use Ks to unwrap the wrapping key */ - unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL, - &wrappedKey, masterWrapMech, - CKA_UNWRAP, 0); - PK11_FreeSymKey(Ks); - - break; -#endif - - default: - /* Assert? */ - SET_ERROR_CODE - goto loser; - } -loser: - return unwrappedWrappingKey; -} - -/* Each process sharing the server session ID cache has its own array of - * SymKey pointers for the symmetric wrapping keys that are used to wrap - * the master secrets. There is one key for each KEA type. These Symkeys - * correspond to the wrapped SymKeys kept in the server session cache. - */ - -typedef struct { - PK11SymKey *symWrapKey[kt_kea_size]; -} ssl3SymWrapKey; - -static PZLock *symWrapKeysLock = NULL; -static ssl3SymWrapKey symWrapKeys[SSL_NUM_WRAP_MECHS]; - -SECStatus -ssl_FreeSymWrapKeysLock(void) -{ - if (symWrapKeysLock) { - PZ_DestroyLock(symWrapKeysLock); - symWrapKeysLock = NULL; - return SECSuccess; - } - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return SECFailure; -} - -SECStatus -SSL3_ShutdownServerCache(void) -{ - int i, j; - - if (!symWrapKeysLock) - return SECSuccess; /* lock was never initialized */ - PZ_Lock(symWrapKeysLock); - /* get rid of all symWrapKeys */ - for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) { - for (j = 0; j < kt_kea_size; ++j) { - PK11SymKey **pSymWrapKey; - pSymWrapKey = &symWrapKeys[i].symWrapKey[j]; - if (*pSymWrapKey) { - PK11_FreeSymKey(*pSymWrapKey); - *pSymWrapKey = NULL; - } - } - } - - PZ_Unlock(symWrapKeysLock); - return SECSuccess; -} - -SECStatus -ssl_InitSymWrapKeysLock(void) -{ - symWrapKeysLock = PZ_NewLock(nssILockOther); - return symWrapKeysLock ? SECSuccess : SECFailure; -} - -/* Try to get wrapping key for mechanism from in-memory array. - * If that fails, look for one on disk. - * If that fails, generate a new one, put the new one on disk, - * Put the new key in the in-memory array. - */ -static PK11SymKey * -getWrappingKey(sslSocket *ss, - PK11SlotInfo *masterSecretSlot, - SSL3KEAType exchKeyType, - CK_MECHANISM_TYPE masterWrapMech, - void *pwArg) -{ - SECKEYPrivateKey *svrPrivKey; - SECKEYPublicKey *svrPubKey = NULL; - PK11SymKey *unwrappedWrappingKey = NULL; - PK11SymKey **pSymWrapKey; - CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM; - int length; - int symWrapMechIndex; - SECStatus rv; - SECItem wrappedKey; - SSLWrappedSymWrappingKey wswk; -#ifndef NSS_DISABLE_ECC - PK11SymKey *Ks = NULL; - SECKEYPublicKey *pubWrapKey = NULL; - SECKEYPrivateKey *privWrapKey = NULL; - ECCWrappedKeyInfo *ecWrapped; -#endif /* NSS_DISABLE_ECC */ - - svrPrivKey = ss->serverCerts[exchKeyType].SERVERKEY; - PORT_Assert(svrPrivKey != NULL); - if (!svrPrivKey) { - return NULL; /* why are we here?!? */ - } - - symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech); - PORT_Assert(symWrapMechIndex >= 0); - if (symWrapMechIndex < 0) - return NULL; /* invalid masterWrapMech. */ - - pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[exchKeyType]; - - ssl_InitSessionCacheLocks(); - - PZ_Lock(symWrapKeysLock); - - unwrappedWrappingKey = *pSymWrapKey; - if (unwrappedWrappingKey != NULL) { - if (PK11_VerifyKeyOK(unwrappedWrappingKey)) { - unwrappedWrappingKey = PK11_ReferenceSymKey(unwrappedWrappingKey); - goto done; - } - /* slot series has changed, so this key is no good any more. */ - PK11_FreeSymKey(unwrappedWrappingKey); - *pSymWrapKey = unwrappedWrappingKey = NULL; - } - - /* Try to get wrapped SymWrapping key out of the (disk) cache. */ - /* Following call fills in wswk on success. */ - if (ssl_GetWrappingKey(symWrapMechIndex, exchKeyType, &wswk)) { - /* found the wrapped sym wrapping key on disk. */ - unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType, - masterWrapMech, pwArg); - if (unwrappedWrappingKey) { - goto install; - } - } - - if (!masterSecretSlot) /* caller doesn't want to create a new one. */ - goto loser; - - length = PK11_GetBestKeyLength(masterSecretSlot, masterWrapMech); - /* Zero length means fixed key length algorithm, or error. - * It's ambiguous. - */ - unwrappedWrappingKey = PK11_KeyGen(masterSecretSlot, masterWrapMech, NULL, - length, pwArg); - if (!unwrappedWrappingKey) { - goto loser; - } - - /* Prepare the buffer to receive the wrappedWrappingKey, - * the symmetric wrapping key wrapped using the server's pub key. - */ - PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */ - - if (ss->serverCerts[exchKeyType].serverKeyPair) { - svrPubKey = ss->serverCerts[exchKeyType].serverKeyPair->pubKey; - } - if (svrPubKey == NULL) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - goto loser; - } - wrappedKey.type = siBuffer; - wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); - wrappedKey.data = wswk.wrappedSymmetricWrappingkey; - - PORT_Assert(wrappedKey.len <= sizeof wswk.wrappedSymmetricWrappingkey); - if (wrappedKey.len > sizeof wswk.wrappedSymmetricWrappingkey) - goto loser; - - /* wrap symmetric wrapping key in server's public key. */ - switch (exchKeyType) { - case kt_rsa: - asymWrapMechanism = CKM_RSA_PKCS; - rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey, - unwrappedWrappingKey, &wrappedKey); - break; - -#ifndef NSS_DISABLE_ECC - case kt_ecdh: - /* - * We generate an ephemeral EC key pair. Perform an ECDH - * computation involving this ephemeral EC public key and - * the SSL server's (long-term) EC private key. The resulting - * shared secret is treated in the same way as Fortezza's Ks, - * i.e., it is used to wrap the wrapping key. To facilitate - * unwrapping in ssl_UnwrapWrappingKey, we also store all - * relevant info about the ephemeral EC public key in - * wswk.wrappedSymmetricWrappingkey and lay it out as - * described in the ECCWrappedKeyInfo structure. - */ - PORT_Assert(svrPubKey->keyType == ecKey); - if (svrPubKey->keyType != ecKey) { - /* something is wrong in sslsecur.c if this isn't an ecKey */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - goto ec_cleanup; - } - - privWrapKey = SECKEY_CreateECPrivateKey( - &svrPubKey->u.ec.DEREncodedParams, &pubWrapKey, NULL); - if ((privWrapKey == NULL) || (pubWrapKey == NULL)) { - rv = SECFailure; - goto ec_cleanup; - } - - /* Set the key size in bits */ - if (pubWrapKey->u.ec.size == 0) { - pubWrapKey->u.ec.size = SECKEY_PublicKeyStrengthInBits(svrPubKey); - } - - PORT_Assert(pubWrapKey->u.ec.DEREncodedParams.len + - pubWrapKey->u.ec.publicValue.len < MAX_EC_WRAPPED_KEY_BUFLEN); - if (pubWrapKey->u.ec.DEREncodedParams.len + - pubWrapKey->u.ec.publicValue.len >= MAX_EC_WRAPPED_KEY_BUFLEN) { - PORT_SetError(SEC_ERROR_INVALID_KEY); - rv = SECFailure; - goto ec_cleanup; - } - - /* Derive Ks using ECDH */ - Ks = PK11_PubDeriveWithKDF(svrPrivKey, pubWrapKey, PR_FALSE, NULL, - NULL, CKM_ECDH1_DERIVE, masterWrapMech, - CKA_DERIVE, 0, CKD_NULL, NULL, NULL); - if (Ks == NULL) { - rv = SECFailure; - goto ec_cleanup; - } - - ecWrapped = (ECCWrappedKeyInfo *)(wswk.wrappedSymmetricWrappingkey); - ecWrapped->size = pubWrapKey->u.ec.size; - ecWrapped->encodedParamLen = pubWrapKey->u.ec.DEREncodedParams.len; - PORT_Memcpy(ecWrapped->var, pubWrapKey->u.ec.DEREncodedParams.data, - pubWrapKey->u.ec.DEREncodedParams.len); - - ecWrapped->pubValueLen = pubWrapKey->u.ec.publicValue.len; - PORT_Memcpy(ecWrapped->var + ecWrapped->encodedParamLen, - pubWrapKey->u.ec.publicValue.data, - pubWrapKey->u.ec.publicValue.len); - - wrappedKey.len = MAX_EC_WRAPPED_KEY_BUFLEN - - (ecWrapped->encodedParamLen + ecWrapped->pubValueLen); - wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen + - ecWrapped->pubValueLen; - - /* wrap symmetricWrapping key with the local Ks */ - rv = PK11_WrapSymKey(masterWrapMech, NULL, Ks, - unwrappedWrappingKey, &wrappedKey); - - if (rv != SECSuccess) { - goto ec_cleanup; - } - - /* Write down the length of wrapped key in the buffer - * wswk.wrappedSymmetricWrappingkey at the appropriate offset - */ - ecWrapped->wrappedKeyLen = wrappedKey.len; - - ec_cleanup: - if (privWrapKey) - SECKEY_DestroyPrivateKey(privWrapKey); - if (pubWrapKey) - SECKEY_DestroyPublicKey(pubWrapKey); - if (Ks) - PK11_FreeSymKey(Ks); - asymWrapMechanism = masterWrapMech; - break; -#endif /* NSS_DISABLE_ECC */ - - default: - rv = SECFailure; - break; - } - - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM); - - wswk.symWrapMechanism = masterWrapMech; - wswk.symWrapMechIndex = symWrapMechIndex; - wswk.asymWrapMechanism = asymWrapMechanism; - wswk.exchKeyType = exchKeyType; - wswk.wrappedSymKeyLen = wrappedKey.len; - - /* put it on disk. */ - /* If the wrapping key for this KEA type has already been set, - * then abandon the value we just computed and - * use the one we got from the disk. - */ - if (ssl_SetWrappingKey(&wswk)) { - /* somebody beat us to it. The original contents of our wswk - * has been replaced with the content on disk. Now, discard - * the key we just created and unwrap this new one. - */ - PK11_FreeSymKey(unwrappedWrappingKey); - - unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType, - masterWrapMech, pwArg); - } - -install: - if (unwrappedWrappingKey) { - *pSymWrapKey = PK11_ReferenceSymKey(unwrappedWrappingKey); - } - -loser: -done: - PZ_Unlock(symWrapKeysLock); - return unwrappedWrappingKey; -} - -/* hexEncode hex encodes |length| bytes from |in| and writes it as |length*2| - * bytes to |out|. */ -static void -hexEncode(char *out, const unsigned char *in, unsigned int length) -{ - static const char hextable[] = "0123456789abcdef"; - unsigned int i; - - for (i = 0; i < length; i++) { - *(out++) = hextable[in[i] >> 4]; - *(out++) = hextable[in[i] & 15]; - } -} - -/* Called from ssl3_SendClientKeyExchange(). */ -/* Presently, this always uses PKCS11. There is no bypass for this. */ -static SECStatus -sendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) -{ - PK11SymKey *pms = NULL; - SECStatus rv = SECFailure; - SECItem enc_pms = { siBuffer, NULL, 0 }; - PRBool isTLS; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - /* Generate the pre-master secret ... */ - ssl_GetSpecWriteLock(ss); - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - - pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL); - ssl_ReleaseSpecWriteLock(ss); - if (pms == NULL) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - /* Get the wrapped (encrypted) pre-master secret, enc_pms */ - enc_pms.len = SECKEY_PublicKeyStrength(svrPubKey); - enc_pms.data = (unsigned char *)PORT_Alloc(enc_pms.len); - if (enc_pms.data == NULL) { - goto loser; /* err set by PORT_Alloc */ - } - - /* wrap pre-master secret in server's public key. */ - rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, pms, &enc_pms); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - if (ssl_keylog_iob) { - SECStatus extractRV = PK11_ExtractKeyValue(pms); - if (extractRV == SECSuccess) { - SECItem *keyData = PK11_GetKeyData(pms); - if (keyData && keyData->data && keyData->len) { -#ifdef TRACE - if (ssl_trace >= 100) { - ssl_PrintBuf(ss, "Pre-Master Secret", - keyData->data, keyData->len); - } -#endif - if (ssl_keylog_iob && enc_pms.len >= 8 && keyData->len == 48) { - /* https://developer.mozilla.org/en/NSS_Key_Log_Format */ - - /* There could be multiple, concurrent writers to the - * keylog, so we have to do everything in a single call to - * fwrite. */ - char buf[4 + 8 * 2 + 1 + 48 * 2 + 1]; - - strcpy(buf, "RSA "); - hexEncode(buf + 4, enc_pms.data, 8); - buf[20] = ' '; - hexEncode(buf + 21, keyData->data, 48); - buf[sizeof(buf) - 1] = '\n'; - - fwrite(buf, sizeof(buf), 1, ssl_keylog_iob); - fflush(ssl_keylog_iob); - } - } - } - } - - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, - isTLS ? enc_pms.len + 2 - : enc_pms.len); - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - if (isTLS) { - rv = ssl3_AppendHandshakeVariable(ss, enc_pms.data, enc_pms.len, 2); - } else { - rv = ssl3_AppendHandshake(ss, enc_pms.data, enc_pms.len); - } - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); - pms = NULL; - - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - rv = SECSuccess; - -loser: - if (enc_pms.data != NULL) { - PORT_Free(enc_pms.data); - } - if (pms != NULL) { - PK11_FreeSymKey(pms); - } - return rv; -} - -/* Called from ssl3_SendClientKeyExchange(). */ -/* Presently, this always uses PKCS11. There is no bypass for this. */ -static SECStatus -sendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) -{ - PK11SymKey *pms = NULL; - SECStatus rv = SECFailure; - PRBool isTLS; - CK_MECHANISM_TYPE target; - - SECKEYDHParams dhParam; /* DH parameters */ - SECKEYPublicKey *pubKey = NULL; /* Ephemeral DH key */ - SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */ - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - - /* Copy DH parameters from server key */ - - if (svrPubKey->keyType != dhKey) { - PORT_SetError(SEC_ERROR_BAD_KEY); - goto loser; - } - dhParam.prime.data = svrPubKey->u.dh.prime.data; - dhParam.prime.len = svrPubKey->u.dh.prime.len; - dhParam.base.data = svrPubKey->u.dh.base.data; - dhParam.base.len = svrPubKey->u.dh.base.len; - - /* Generate ephemeral DH keypair */ - privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL); - if (!privKey || !pubKey) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - goto loser; - } - PRINT_BUF(50, (ss, "DH public value:", - pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len)); - - if (isTLS) - target = CKM_TLS_MASTER_KEY_DERIVE_DH; - else - target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - - /* Determine the PMS */ - - pms = PK11_PubDerive(privKey, svrPubKey, PR_FALSE, NULL, NULL, - CKM_DH_PKCS_DERIVE, target, CKA_DERIVE, 0, NULL); - - if (pms == NULL) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - SECKEY_DestroyPrivateKey(privKey); - privKey = NULL; - - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, - pubKey->u.dh.publicValue.len + 2); - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - rv = ssl3_AppendHandshakeVariable(ss, - pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len, 2); - SECKEY_DestroyPublicKey(pubKey); - pubKey = NULL; - - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); - pms = NULL; - - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - rv = SECSuccess; - -loser: - - if (pms) - PK11_FreeSymKey(pms); - if (privKey) - SECKEY_DestroyPrivateKey(privKey); - if (pubKey) - SECKEY_DestroyPublicKey(pubKey); - return rv; -} - -/* Called from ssl3_HandleServerHelloDone(). */ -static SECStatus -ssl3_SendClientKeyExchange(sslSocket *ss) -{ - SECKEYPublicKey *serverKey = NULL; - SECStatus rv = SECFailure; - PRBool isTLS; - - SSL_TRC(3, ("%d: SSL3[%d]: send client_key_exchange handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->sec.peerKey == NULL) { - serverKey = CERT_ExtractPublicKey(ss->sec.peerCert); - if (serverKey == NULL) { - ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - return SECFailure; - } - } else { - serverKey = ss->sec.peerKey; - ss->sec.peerKey = NULL; /* we're done with it now */ - } - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - /* enforce limits on kea key sizes. */ - if (ss->ssl3.hs.kea_def->is_limited) { - unsigned int keyLen = SECKEY_PublicKeyStrengthInBits(serverKey); - - if (keyLen > ss->ssl3.hs.kea_def->key_size_limit) { - if (isTLS) - (void)SSL3_SendAlert(ss, alert_fatal, export_restriction); - else - (void)ssl3_HandshakeFailure(ss); - PORT_SetError(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED); - goto loser; - } - } - - ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; - ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey); - - switch (ss->ssl3.hs.kea_def->exchKeyType) { - case kt_rsa: - rv = sendRSAClientKeyExchange(ss, serverKey); - break; - - case kt_dh: - rv = sendDHClientKeyExchange(ss, serverKey); - break; - -#ifndef NSS_DISABLE_ECC - case kt_ecdh: - rv = ssl3_SendECDHClientKeyExchange(ss, serverKey); - break; -#endif /* NSS_DISABLE_ECC */ - - default: - /* got an unknown or unsupported Key Exchange Algorithm. */ - SEND_ALERT - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); - break; - } - - SSL_TRC(3, ("%d: SSL3[%d]: DONE sending client_key_exchange", - SSL_GETPID(), ss->fd)); - -loser: - if (serverKey) - SECKEY_DestroyPublicKey(serverKey); - return rv; /* err code already set. */ -} - -/* Called from ssl3_HandleServerHelloDone(). */ -SECStatus -ssl3_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey) -{ - SECStatus rv = SECFailure; - PRBool isTLS; - PRBool isTLS12; - PRBool isTLS13; - SECItem buf = { siBuffer, NULL, 0 }; - SSL3Hashes hashes; - KeyType keyType; - unsigned int len; - SSLSignatureAndHashAlg sigAndHash; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake", - SSL_GETPID(), ss->fd)); - - isTLS13 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - ssl_GetSpecReadLock(ss); - if (ss->ssl3.hs.hashType == handshake_hash_single && - ss->ssl3.hs.backupHash) { - PORT_Assert(!ss->ssl3.hs.backupHash); - PORT_Assert(!isTLS13); - /* TODO(ekr@rtfm.com): The backup hash here contains a SHA-1 hash - * but in TLS 1.3, we always sign H(Context, Hash(handshake)) - * where: - * - * H is the negotiated signature hash and - * Hash is the cipher-suite specific handshake hash - * Generally this means that Hash is SHA-256. - * - * We need code to negotiate H but the current code is a mess. - */ - if (isTLS13) { - /* rv is already set to SECFailure */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } else { - rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes); - } - } else { - ssl3CipherSpec *spec; - - if (isTLS13) { - /* In TLS 1.3, we are already encrypted. */ - spec = ss->ssl3.cwSpec; - } else { - spec = ss->ssl3.pwSpec; - } - - rv = ssl3_ComputeHandshakeHashes(ss, spec, &hashes, 0); - } - ssl_ReleaseSpecReadLock(ss); - if (rv != SECSuccess) { - goto done; /* err code was set by ssl3_ComputeHandshakeHashes */ - } - - if (isTLS13) { - rv = tls13_AddContextToHashes(ss, &hashes, tls13_GetHash(ss), PR_TRUE); - if (rv != SECSuccess) { - goto done; /* err code was set by tls13_AddContextToHashes */ - } - } - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - keyType = privKey->keyType; - rv = ssl3_SignHashes(&hashes, privKey, &buf, isTLS); - if (rv == SECSuccess && !ss->sec.isServer) { - /* Remember the info about the slot that did the signing. - ** Later, when doing an SSL restart handshake, verify this. - ** These calls are mere accessors, and can't fail. - */ - PK11SlotInfo *slot; - sslSessionID *sid = ss->sec.ci.sid; - - slot = PK11_GetSlotFromPrivateKey(privKey); - sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot); - sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot); - sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot); - sid->u.ssl3.clAuthValid = PR_TRUE; - PK11_FreeSlot(slot); - } - if (rv != SECSuccess) { - goto done; /* err code was set by ssl3_SignHashes */ - } - - len = buf.len + 2 + (isTLS12 ? 2 : 0); - - rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); - if (rv != SECSuccess) { - goto done; /* error code set by AppendHandshake */ - } - if (isTLS12) { - rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType, - &sigAndHash.sigAlg); - if (rv != SECSuccess) { - goto done; - } - sigAndHash.hashAlg = hashes.hashAlg; - - rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); - if (rv != SECSuccess) { - goto done; /* err set by AppendHandshake. */ - } - } - rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2); - if (rv != SECSuccess) { - goto done; /* error code set by AppendHandshake */ - } - -done: - if (buf.data) - PORT_Free(buf.data); - return rv; -} - -/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete - * ssl3 ServerHello message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - sslSessionID *sid = ss->sec.ci.sid; - PRInt32 temp; /* allow for consume number failure */ - PRBool suite_found = PR_FALSE; - int i; - int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; - SECStatus rv; - SECItem sidBytes = { siBuffer, NULL, 0 }; - PRBool sid_match; - PRBool isTLS = PR_FALSE; - SSL3AlertDescription desc = illegal_parameter; - SSL3ProtocolVersion version; - SSL3ProtocolVersion downgradeCheckVersion; - - SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.initialized); - - if (ss->ssl3.hs.ws != wait_server_hello) { - errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO; - desc = unexpected_message; - goto alert_loser; - } - - /* clean up anything left from previous handshake. */ - if (ss->ssl3.clientCertChain != NULL) { - CERT_DestroyCertificateList(ss->ssl3.clientCertChain); - ss->ssl3.clientCertChain = NULL; - } - if (ss->ssl3.clientCertificate != NULL) { - CERT_DestroyCertificate(ss->ssl3.clientCertificate); - ss->ssl3.clientCertificate = NULL; - } - if (ss->ssl3.clientPrivateKey != NULL) { - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - ss->ssl3.clientPrivateKey = NULL; - } - - if (ss->ssl3.channelID != NULL) { - SECKEY_DestroyPrivateKey(ss->ssl3.channelID); - ss->ssl3.channelID = NULL; - } - if (ss->ssl3.channelIDPub != NULL) { - SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); - ss->ssl3.channelIDPub = NULL; - } - - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (temp < 0) { - goto loser; /* alert has been sent */ - } - version = (SSL3ProtocolVersion)temp; - - if (IS_DTLS(ss)) { - /* RFC 4347 required that you verify that the server versions - * match (Section 4.2.1) in the HelloVerifyRequest and the - * ServerHello. - * - * RFC 6347 suggests (SHOULD) that servers always use 1.0 - * in HelloVerifyRequest and allows the versions not to match, - * especially when 1.2 is being negotiated. - * - * Therefore we do not check for matching here. - */ - version = dtls_DTLSVersionToTLSVersion(version); - if (version == 0) { /* Insane version number */ - goto alert_loser; - } - } - - rv = ssl3_NegotiateVersion(ss, version, PR_FALSE); - if (rv != SECSuccess) { - desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version - : handshake_failure; - errCode = SSL_ERROR_UNSUPPORTED_VERSION; - goto alert_loser; - } - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; - isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); - - rv = ssl3_InitHandshakeHashes(ss); - if (rv != SECSuccess) { - desc = internal_error; - errCode = PORT_GetError(); - goto alert_loser; - } - - rv = ssl3_ConsumeHandshake( - ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); - if (rv != SECSuccess) { - goto loser; /* alert has been sent */ - } - - /* Check the ServerHello.random per - * [draft-ietf-tls-tls13-11 Section 6.3.1.1]. - * - * TLS 1.3 clients receiving a TLS 1.2 or below ServerHello MUST check - * that the top eight octets are not equal to either of these values. - * TLS 1.2 clients SHOULD also perform this check if the ServerHello - * indicates TLS 1.1 or below. If a match is found the client MUST - * abort the handshake with a fatal "illegal_parameter" alert. - */ - downgradeCheckVersion = ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion - : ss->vrange.max; - - if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 && - downgradeCheckVersion > ss->version) { - if (!PORT_Memcmp(ss->ssl3.hs.server_random.rand, - tls13_downgrade_random, - sizeof(tls13_downgrade_random)) || - !PORT_Memcmp(ss->ssl3.hs.server_random.rand, - tls12_downgrade_random, - sizeof(tls12_downgrade_random))) { - desc = illegal_parameter; - errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; - goto alert_loser; - } - } - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* alert has been sent */ - } - if (sidBytes.len > SSL3_SESSIONID_BYTES) { - if (isTLS) - desc = decode_error; - goto alert_loser; /* malformed. */ - } - } - - /* find selected cipher suite in our list. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (temp < 0) { - goto loser; /* alert has been sent */ - } - ssl3_config_match_init(ss); - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (temp == suite->cipher_suite) { - SSLVersionRange vrange = { ss->version, ss->version }; - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) { - /* config_match already checks whether the cipher suite is - * acceptable for the version, but the check is repeated here - * in order to give a more precise error code. */ - if (!ssl3_CipherSuiteAllowedForVersionRange(temp, &vrange)) { - desc = handshake_failure; - errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION; - goto alert_loser; - } - - break; /* failure */ - } - - suite_found = PR_TRUE; - break; /* success */ - } - } - if (!suite_found) { - desc = handshake_failure; - errCode = SSL_ERROR_NO_CYPHER_OVERLAP; - goto alert_loser; - } - ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)temp; - ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp); - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite; - PORT_Assert(ss->ssl3.hs.suite_def); - if (!ss->ssl3.hs.suite_def) { - errCode = SEC_ERROR_LIBRARY_FAILURE; - PORT_SetError(errCode); - goto loser; /* we don't send alerts for our screw-ups. */ - } - - ss->ssl3.hs.kea_def = &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg]; - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - /* find selected compression method in our list. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length); - if (temp < 0) { - goto loser; /* alert has been sent */ - } - suite_found = PR_FALSE; - for (i = 0; i < compressionMethodsCount; i++) { - if (temp == compressions[i]) { - if (!compressionEnabled(ss, compressions[i])) { - break; /* failure */ - } - suite_found = PR_TRUE; - break; /* success */ - } - } - if (!suite_found) { - desc = handshake_failure; - errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP; - goto alert_loser; - } - ss->ssl3.hs.compression = (SSLCompressionMethod)temp; - } else { - ss->ssl3.hs.compression = ssl_compression_null; - } - - /* Note that if !isTLS and the extra stuff is not extensions, we - * do NOT goto alert_loser. - * There are some old SSL 3.0 implementations that do send stuff - * after the end of the server hello, and we deliberately ignore - * such stuff in the interest of maximal interoperability (being - * "generous in what you accept"). - * Update: Starting in NSS 3.12.6, we handle the renegotiation_info - * extension in SSL 3.0. - */ - if (length != 0) { - SECItem extensions; - rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length); - if (rv != SECSuccess || length != 0) { - if (isTLS) - goto alert_loser; - } else { - rv = ssl3_HandleHelloExtensions(ss, &extensions.data, - &extensions.len, server_hello); - if (rv != SECSuccess) - goto alert_loser; - } - } - if ((ss->opt.requireSafeNegotiation || - (ss->firstHsDone && (ss->peerRequestedProtection || - ss->opt.enableRenegotiation == - SSL_RENEGOTIATE_REQUIRES_XTN))) && - !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - desc = handshake_failure; - errCode = ss->firstHsDone ? SSL_ERROR_RENEGOTIATION_NOT_ALLOWED - : SSL_ERROR_UNSAFE_NEGOTIATION; - goto alert_loser; - } - - /* Any errors after this point are not "malformed" errors. */ - desc = handshake_failure; - - /* we need to call ssl3_SetupPendingCipherSpec here so we can check the - * key exchange algorithm. */ - rv = ssl3_SetupPendingCipherSpec(ss); - if (rv != SECSuccess) { - goto alert_loser; /* error code is set. */ - } - - /* We may or may not have sent a session id, we may get one back or - * not and if so it may match the one we sent. - * Attempt to restore the master secret to see if this is so... - * Don't consider failure to find a matching SID an error. - */ - sid_match = (PRBool)(sidBytes.len > 0 && - sidBytes.len == - sid->u.ssl3.sessionIDLength && - !PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len)); - - if (sid_match && - sid->version == ss->version && - sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) - do { - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - - SECItem wrappedMS; /* wrapped master secret. */ - - /* [draft-ietf-tls-session-hash-06; Section 5.3] - * - * o If the original session did not use the "extended_master_secret" - * extension but the new ServerHello contains the extension, the - * client MUST abort the handshake. - */ - if (!sid->u.ssl3.keys.extendedMasterSecretUsed && - ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) { - errCode = SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET; - goto alert_loser; - } - - /* - * o If the original session used an extended master secret but the new - * ServerHello does not contain the "extended_master_secret" - * extension, the client SHOULD abort the handshake. - * - * TODO(ekr@rtfm.com): Add option to refuse to resume when EMS is not - * used at all (bug 1176526). - */ - if (sid->u.ssl3.keys.extendedMasterSecretUsed && - !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) { - errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET; - goto alert_loser; - } - - ss->sec.authAlgorithm = sid->authAlgorithm; - ss->sec.authKeyBits = sid->authKeyBits; - ss->sec.keaType = sid->keaType; - ss->sec.keaKeyBits = sid->keaKeyBits; - - /* 3 cases here: - * a) key is wrapped (implies using PKCS11) - * b) key is unwrapped, but we're still using PKCS11 - * c) key is unwrapped, and we're bypassing PKCS11. - */ - if (sid->u.ssl3.keys.msIsWrapped) { - PK11SlotInfo *slot; - PK11SymKey *wrapKey; /* wrapping key */ - CK_FLAGS keyFlags = 0; - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - /* we cannot restart a non-bypass session in a - ** bypass socket. - */ - break; - } -#endif - /* unwrap master secret with PKCS11 */ - slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, - sid->u.ssl3.masterSlotID); - if (slot == NULL) { - break; /* not considered an error. */ - } - if (!PK11_IsPresent(slot)) { - PK11_FreeSlot(slot); - break; /* not considered an error. */ - } - wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex, - sid->u.ssl3.masterWrapMech, - sid->u.ssl3.masterWrapSeries, - ss->pkcs11PinArg); - PK11_FreeSlot(slot); - if (wrapKey == NULL) { - break; /* not considered an error. */ - } - - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - keyFlags = - CKF_SIGN | CKF_VERIFY; - } - - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - pwSpec->master_secret = - PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, - NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, - CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); - errCode = PORT_GetError(); - PK11_FreeSymKey(wrapKey); - if (pwSpec->master_secret == NULL) { - break; /* errorCode set just after call to UnwrapSymKey. */ - } -#ifndef NO_PKCS11_BYPASS - } else if (ss->opt.bypassPKCS11) { - /* MS is not wrapped */ - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len); - pwSpec->msItem.data = pwSpec->raw_master_secret; - pwSpec->msItem.len = wrappedMS.len; -#endif - } else { - /* We CAN restart a bypass session in a non-bypass socket. */ - /* need to import the raw master secret to session object */ - PK11SlotInfo *slot = PK11_GetInternalSlot(); - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - pwSpec->master_secret = - PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, - PK11_OriginUnwrap, CKA_ENCRYPT, - &wrappedMS, NULL); - PK11_FreeSlot(slot); - if (pwSpec->master_secret == NULL) { - break; - } - } - - /* Got a Match */ - SSL_AtomicIncrementLong(&ssl3stats.hsh_sid_cache_hits); - - /* If we sent a session ticket, then this is a stateless resume. */ - if (ss->xtnData.sentSessionTicketInClientHello) - SSL_AtomicIncrementLong(&ssl3stats.hsh_sid_stateless_resumes); - - if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) - ss->ssl3.hs.ws = wait_new_session_ticket; - else - ss->ssl3.hs.ws = wait_change_cipher; - - ss->ssl3.hs.isResuming = PR_TRUE; - - /* copy the peer cert from the SID */ - if (sid->peerCert != NULL) { - ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); - ssl3_CopyPeerCertsFromSID(ss, sid); - } - - /* NULL value for PMS because we are reusing the old MS */ - rv = ssl3_InitPendingCipherSpec(ss, NULL); - if (rv != SECSuccess) { - goto alert_loser; /* err code was set */ - } - goto winner; - } while (0); - - if (sid_match) - SSL_AtomicIncrementLong(&ssl3stats.hsh_sid_cache_not_ok); - else - SSL_AtomicIncrementLong(&ssl3stats.hsh_sid_cache_misses); - - /* throw the old one away */ - sid->u.ssl3.keys.resumable = PR_FALSE; - if (ss->sec.uncache) - (*ss->sec.uncache)(sid); - ssl_FreeSID(sid); - - /* get a new sid */ - ss->sec.ci.sid = sid = ssl3_NewSessionID(ss, PR_FALSE); - if (sid == NULL) { - goto alert_loser; /* memory error is set. */ - } - - sid->version = ss->version; - sid->u.ssl3.sessionIDLength = sidBytes.len; - PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len); - - sid->u.ssl3.keys.extendedMasterSecretUsed = - ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn); - - /* Copy Signed Certificate Timestamps, if any. */ - if (ss->xtnData.signedCertTimestamps.data) { - rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.signedCertTimestamps, - &ss->xtnData.signedCertTimestamps); - if (rv != SECSuccess) - goto loser; - /* Clean up the temporary pointer to the handshake buffer. */ - ss->xtnData.signedCertTimestamps.data = NULL; - ss->xtnData.signedCertTimestamps.len = 0; - } - - ss->ssl3.hs.isResuming = PR_FALSE; - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - rv = tls13_HandleServerKeyShare(ss); - if (rv != SECSuccess) - goto alert_loser; - TLS13_SET_HS_STATE(ss, wait_encrypted_extensions); - } else if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_null) { - /* All current cipher suites other than those with ssl_sign_null (i.e., - * (EC)DH_anon_* suites) require a certificate, so use that signal. */ - ss->ssl3.hs.ws = wait_server_cert; - } else { - /* All the remaining cipher suites must be (EC)DH_anon_* and so - * must be ephemeral. Note, if we ever add PSK this might - * change. */ - PORT_Assert(ss->ssl3.hs.kea_def->ephemeral); - ss->ssl3.hs.ws = wait_server_key; - } - -winner: - /* If we will need a ChannelID key then we make the callback now. This - * allows the handshake to be restarted cleanly if the callback returns - * SECWouldBlock. */ - if (ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { - rv = ss->getChannelID(ss->getChannelIDArg, ss->fd, - &ss->ssl3.channelIDPub, &ss->ssl3.channelID); - if (rv == SECWouldBlock) { - ssl3_SetAlwaysBlock(ss); - return rv; - } - if (rv != SECSuccess || - ss->ssl3.channelIDPub == NULL || - ss->ssl3.channelID == NULL) { - PORT_SetError(SSL_ERROR_GET_CHANNEL_ID_FAILED); - desc = internal_error; - goto alert_loser; - } - } - - return SECSuccess; - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, desc); - -loser: - /* Clean up the temporary pointer to the handshake buffer. */ - ss->xtnData.signedCertTimestamps.data = NULL; - ss->xtnData.signedCertTimestamps.len = 0; - ssl_MapLowLevelError(errCode); - return SECFailure; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a - * complete ssl3 ServerKeyExchange message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - PLArenaPool *arena = NULL; - SECKEYPublicKey *peerKey = NULL; - PRBool isTLS, isTLS12; - SECStatus rv; - int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; - SSL3AlertDescription desc = illegal_parameter; - SSL3Hashes hashes; - SECItem signature = { siBuffer, NULL, 0 }; - SSLSignatureAndHashAlg sigAndHash; - - sigAndHash.hashAlg = ssl_hash_none; - - SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.hs.ws != wait_server_key) { - errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH; - desc = unexpected_message; - goto alert_loser; - } - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - switch (ss->ssl3.hs.kea_def->exchKeyType) { - - case kt_rsa: { - SECItem modulus = { siBuffer, NULL, 0 }; - SECItem exponent = { siBuffer, NULL, 0 }; - - rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - /* This exchange method is only used by export cipher suites. - * Those are broken and so this code will eventually be removed. */ - if (SECKEY_BigIntegerBitLength(&modulus) < 512) { - desc = isTLS ? insufficient_security : illegal_parameter; - goto alert_loser; - } - rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - if (isTLS12) { - rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, - &sigAndHash); - if (rv != SECSuccess) { - goto loser; /* malformed or unsupported. */ - } - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(ss, - &sigAndHash, ss->sec.peerCert); - if (rv != SECSuccess) { - goto loser; - } - } - rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - if (length != 0) { - if (isTLS) - desc = - decode_error; - goto alert_loser; /* malformed. */ - } - - /* failures after this point are not malformed handshakes. */ - /* TLS: send decrypt_error if signature failed. */ - desc = isTLS ? decrypt_error : handshake_failure; - - /* - * check to make sure the hash is signed by right guy - */ - rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, - isTLS, ss->pkcs11PinArg); - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - - /* - * we really need to build a new key here because we can no longer - * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate - * pkcs11 slots and ID's. - */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto no_memory; - } - - peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); - if (peerKey == NULL) { - goto no_memory; - } - - peerKey->arena = arena; - peerKey->keyType = rsaKey; - peerKey->pkcs11Slot = NULL; - peerKey->pkcs11ID = CK_INVALID_HANDLE; - if (SECITEM_CopyItem(arena, &peerKey->u.rsa.modulus, &modulus) || - SECITEM_CopyItem(arena, &peerKey->u.rsa.publicExponent, &exponent)) { - goto no_memory; - } - ss->sec.peerKey = peerKey; - ss->ssl3.hs.ws = wait_cert_request; - return SECSuccess; - } - - case kt_dh: { - SECItem dh_p = { siBuffer, NULL, 0 }; - SECItem dh_g = { siBuffer, NULL, 0 }; - SECItem dh_Ys = { siBuffer, NULL, 0 }; - unsigned dh_p_bits; - unsigned dh_g_bits; - unsigned dh_Ys_bits; - PRInt32 minDH; - - rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - - rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH); - if (rv != SECSuccess) { - minDH = SSL_DH_MIN_P_BITS; - } - dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p); - if (dh_p_bits < minDH) { - errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY; - goto alert_loser; - } - rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - /* Abort if dh_g is 0, 1, or obviously too big. */ - dh_g_bits = SECKEY_BigIntegerBitLength(&dh_g); - if (dh_g_bits > dh_p_bits || dh_g_bits <= 1) - goto alert_loser; - rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - dh_Ys_bits = SECKEY_BigIntegerBitLength(&dh_Ys); - if (dh_Ys_bits > dh_p_bits || dh_Ys_bits <= 1) - goto alert_loser; - if (isTLS12) { - rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, - &sigAndHash); - if (rv != SECSuccess) { - goto loser; /* malformed or unsupported. */ - } - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(ss, - &sigAndHash, ss->sec.peerCert); - if (rv != SECSuccess) { - goto loser; - } - } - rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - if (length != 0) { - if (isTLS) - desc = - decode_error; - goto alert_loser; /* malformed. */ - } - - PRINT_BUF(60, (NULL, "Server DH p", dh_p.data, dh_p.len)); - PRINT_BUF(60, (NULL, "Server DH g", dh_g.data, dh_g.len)); - PRINT_BUF(60, (NULL, "Server DH Ys", dh_Ys.data, dh_Ys.len)); - - /* failures after this point are not malformed handshakes. */ - /* TLS: send decrypt_error if signature failed. */ - desc = isTLS ? decrypt_error : handshake_failure; - - /* - * check to make sure the hash is signed by right guy - */ - rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, - isTLS, ss->pkcs11PinArg); - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - - /* - * we really need to build a new key here because we can no longer - * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate - * pkcs11 slots and ID's. - */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto no_memory; - } - - peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); - if (peerKey == NULL) { - goto no_memory; - } - - peerKey->arena = arena; - peerKey->keyType = dhKey; - peerKey->pkcs11Slot = NULL; - peerKey->pkcs11ID = CK_INVALID_HANDLE; - - if (SECITEM_CopyItem(arena, &peerKey->u.dh.prime, &dh_p) || - SECITEM_CopyItem(arena, &peerKey->u.dh.base, &dh_g) || - SECITEM_CopyItem(arena, &peerKey->u.dh.publicValue, &dh_Ys)) { - goto no_memory; - } - ss->sec.peerKey = peerKey; - ss->ssl3.hs.ws = wait_cert_request; - return SECSuccess; - } - -#ifndef NSS_DISABLE_ECC - case kt_ecdh: - rv = ssl3_HandleECDHServerKeyExchange(ss, b, length); - return rv; -#endif /* NSS_DISABLE_ECC */ - - default: - desc = handshake_failure; - errCode = SEC_ERROR_UNSUPPORTED_KEYALG; - break; /* goto alert_loser; */ - } - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, desc); -loser: - if (arena) { - PORT_FreeArena(arena, PR_FALSE); - } - PORT_SetError(errCode); - return SECFailure; - -no_memory: /* no-memory error has already been set. */ - if (arena) { - PORT_FreeArena(arena, PR_FALSE); - } - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return SECFailure; -} - -/* - * Returns the TLS signature algorithm for the client authentication key and - * whether it is an RSA or DSA key that may be able to sign only SHA-1 hashes. - */ -static SECStatus -ssl3_ExtractClientKeyInfo(sslSocket *ss, - SSLSignType *sigAlg, - PRBool *preferSha1) -{ - SECStatus rv = SECSuccess; - SECKEYPublicKey *pubk; - - pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); - if (pubk == NULL) { - rv = SECFailure; - goto done; - } - - rv = ssl3_TLSSignatureAlgorithmForKeyType(pubk->keyType, sigAlg); - if (rv != SECSuccess) { - goto done; - } - - /* If the key is a 1024-bit RSA or DSA key, assume conservatively that - * it may be unable to sign SHA-256 hashes. This is the case for older - * Estonian ID cards that have 1024-bit RSA keys. In FIPS 186-2 and - * older, DSA key size is at most 1024 bits and the hash function must - * be SHA-1. - */ - if (pubk->keyType == rsaKey || pubk->keyType == dsaKey) { - *preferSha1 = SECKEY_PublicKeyStrength(pubk) <= 128; - } else { - *preferSha1 = PR_FALSE; - } - -done: - if (pubk) - SECKEY_DestroyPublicKey(pubk); - return rv; -} - -/* Destroys the backup handshake hash context if we don't need it. Note that - * this function selects the hash algorithm for client authentication - * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash - * to determine whether to use SHA-1 or SHA-256. */ -static void -ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss, - const SECItem *algorithms) -{ - SECStatus rv; - SSLSignType sigAlg; - PRBool preferSha1 = PR_FALSE; - PRBool supportsSha1 = PR_FALSE; - PRBool supportsSha256 = PR_FALSE; - PRBool needBackupHash = PR_FALSE; - unsigned int i; - -#ifndef NO_PKCS11_BYPASS - /* Backup handshake hash is not supported in PKCS #11 bypass mode. */ - if (ss->opt.bypassPKCS11) { - PORT_Assert(!ss->ssl3.hs.backupHash); - return; - } -#endif - PORT_Assert(ss->ssl3.hs.backupHash); - - /* Determine the key's signature algorithm and whether it prefers SHA-1. */ - rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1); - if (rv != SECSuccess) { - goto done; - } - - /* Determine the server's hash support for that signature algorithm. */ - for (i = 0; i < algorithms->len; i += 2) { - if (algorithms->data[i + 1] == sigAlg) { - if (algorithms->data[i] == ssl_hash_sha1) { - supportsSha1 = PR_TRUE; - } else if (algorithms->data[i] == ssl_hash_sha256) { - supportsSha256 = PR_TRUE; - } - } - } - - /* If either the server does not support SHA-256 or the client key prefers - * SHA-1, leave the backup hash. */ - if (supportsSha1 && (preferSha1 || !supportsSha256)) { - needBackupHash = PR_TRUE; - } - -done: - if (!needBackupHash) { - PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE); - ss->ssl3.hs.backupHash = NULL; - } -} - -typedef struct dnameNode { - struct dnameNode *next; - SECItem name; -} dnameNode; - -/* - * Parse the ca_list structure in a CertificateRequest. - * - * Called from: - * ssl3_HandleCertificateRequest - * tls13_HandleCertificateRequest - */ -SECStatus -ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, PRUint32 *length, - PLArenaPool *arena, CERTDistNames *ca_list) -{ - PRInt32 remaining; - int nnames = 0; - dnameNode *node; - int i; - - remaining = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (remaining < 0) - return SECFailure; /* malformed, alert has been sent */ - - if ((PRUint32)remaining > *length) - goto alert_loser; - - ca_list->head = node = PORT_ArenaZNew(arena, dnameNode); - if (node == NULL) - goto no_mem; - - while (remaining > 0) { - PRInt32 len; - - if (remaining < 2) - goto alert_loser; /* malformed */ - - node->name.len = len = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (len <= 0) - return SECFailure; /* malformed, alert has been sent */ - - remaining -= 2; - if (remaining < len) - goto alert_loser; /* malformed */ - - node->name.data = *b; - *b += len; - *length -= len; - remaining -= len; - nnames++; - if (remaining <= 0) - break; /* success */ - - node->next = PORT_ArenaZNew(arena, dnameNode); - node = node->next; - if (node == NULL) - goto no_mem; - } - - ca_list->nnames = nnames; - ca_list->names = PORT_ArenaNewArray(arena, SECItem, nnames); - if (nnames > 0 && ca_list->names == NULL) - goto no_mem; - - for (i = 0, node = (dnameNode *)ca_list->head; - i < nnames; - i++, node = node->next) { - ca_list->names[i] = node->name; - } - - return SECSuccess; - -no_mem: - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, - ss->version < SSL_LIBRARY_VERSION_TLS_1_0 ? illegal_parameter - : decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); - return SECFailure; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 Certificate Request message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - PLArenaPool *arena = NULL; - PRBool isTLS = PR_FALSE; - PRBool isTLS12 = PR_FALSE; - int errCode = SSL_ERROR_RX_MALFORMED_CERT_REQUEST; - SECStatus rv; - SSL3AlertDescription desc = illegal_parameter; - SECItem cert_types = { siBuffer, NULL, 0 }; - SECItem algorithms = { siBuffer, NULL, 0 }; - CERTDistNames ca_list; - - SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.hs.ws != wait_cert_request) { - desc = unexpected_message; - errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST; - goto alert_loser; - } - - PORT_Assert(ss->ssl3.clientCertChain == NULL); - PORT_Assert(ss->ssl3.clientCertificate == NULL); - PORT_Assert(ss->ssl3.clientPrivateKey == NULL); - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); - if (rv != SECSuccess) - goto loser; /* malformed, alert has been sent */ - - PORT_Assert(!ss->requestedCertTypes); - ss->requestedCertTypes = &cert_types; - - if (isTLS12) { - rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &b, &length); - if (rv != SECSuccess) - goto loser; /* malformed, alert has been sent */ - /* An empty or odd-length value is invalid. - * SignatureAndHashAlgorithm - * supported_signature_algorithms<2..2^16-2>; - */ - if (algorithms.len == 0 || (algorithms.len & 1) != 0) - goto alert_loser; - } - - arena = ca_list.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) - goto no_mem; - - rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list); - if (rv != SECSuccess) - goto done; /* alert sent in ssl3_ParseCertificateRequestCAs */ - - if (length != 0) - goto alert_loser; /* malformed */ - - desc = no_certificate; - - ss->ssl3.hs.ws = wait_hello_done; - - rv = ssl3_CompleteHandleCertificateRequest(ss, &algorithms, &ca_list); - if (rv == SECFailure) { - PORT_Assert(0); - errCode = SEC_ERROR_LIBRARY_FAILURE; - desc = internal_error; - goto alert_loser; - } - goto done; - -no_mem: - rv = SECFailure; - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto done; - -alert_loser: - if (isTLS && desc == illegal_parameter) - desc = decode_error; - (void)SSL3_SendAlert(ss, alert_fatal, desc); -loser: - PORT_SetError(errCode); - rv = SECFailure; -done: - ss->requestedCertTypes = NULL; - if (arena != NULL) - PORT_FreeArena(arena, PR_FALSE); - return rv; -} - -SECStatus -ssl3_CompleteHandleCertificateRequest(sslSocket *ss, SECItem *algorithms, - CERTDistNames *ca_list) -{ - SECStatus rv; - - if (ss->getClientAuthData != NULL) { - PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == - ssl_preinfo_all); - /* XXX Should pass cert_types and algorithms in this call!! */ - rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg, - ss->fd, ca_list, - &ss->ssl3.clientCertificate, - &ss->ssl3.clientPrivateKey); - } else { - rv = SECFailure; /* force it to send a no_certificate alert */ - } - switch (rv) { - case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ - ssl3_SetAlwaysBlock(ss); - break; /* not an error */ - - case SECSuccess: - /* check what the callback function returned */ - if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { - /* we are missing either the key or cert */ - if (ss->ssl3.clientCertificate) { - /* got a cert, but no key - free it */ - CERT_DestroyCertificate(ss->ssl3.clientCertificate); - ss->ssl3.clientCertificate = NULL; - } - if (ss->ssl3.clientPrivateKey) { - /* got a key, but no cert - free it */ - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - ss->ssl3.clientPrivateKey = NULL; - } - goto send_no_certificate; - } - /* Setting ssl3.clientCertChain non-NULL will cause - * ssl3_HandleServerHelloDone to call SendCertificate. - */ - ss->ssl3.clientCertChain = CERT_CertChainFromCert( - ss->ssl3.clientCertificate, - certUsageSSLClient, PR_FALSE); - if (ss->ssl3.clientCertChain == NULL) { - CERT_DestroyCertificate(ss->ssl3.clientCertificate); - ss->ssl3.clientCertificate = NULL; - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - ss->ssl3.clientPrivateKey = NULL; - goto send_no_certificate; - } - if (ss->ssl3.hs.hashType == handshake_hash_single) { - ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, algorithms); - } - break; /* not an error */ - - case SECFailure: - default: - send_no_certificate: - if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { - ss->ssl3.sendEmptyCert = PR_TRUE; - } else { - (void)SSL3_SendAlert(ss, alert_warning, no_certificate); - } - rv = SECSuccess; - break; - } - - return rv; -} - -/* - * attempt to restart the handshake after asynchronously handling - * a request for the client's certificate. - * - * inputs: - * cert Client cert chosen by application. - * Note: ssl takes this reference, and does not bump the - * reference count. The caller should drop its reference - * without calling CERT_DestroyCert after calling this function. - * - * key Private key associated with cert. This function takes - * ownership of the private key, so the caller should drop its - * reference without destroying the private key after this - * function returns. - * - * certChain DER-encoded certs, client cert and its signers. - * Note: ssl takes this reference, and does not copy the chain. - * The caller should drop its reference without destroying the - * chain. SSL will free the chain when it is done with it. - * - * Return value: XXX - * - * XXX This code only works on the initial handshake on a connection, XXX - * It does not work on a subsequent handshake (redo). - * - * Caller holds 1stHandshakeLock. - */ -SECStatus -ssl3_RestartHandshakeAfterCertReq(sslSocket *ss, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain) -{ - SECStatus rv = SECSuccess; - - /* XXX This code only works on the initial handshake on a connection, - ** XXX It does not work on a subsequent handshake (redo). - */ - if (ss->handshake != 0) { - ss->handshake = ssl_GatherRecord1stHandshake; - ss->ssl3.clientCertificate = cert; - ss->ssl3.clientPrivateKey = key; - ss->ssl3.clientCertChain = certChain; - if (!cert || !key || !certChain) { - /* we are missing the key, cert, or cert chain */ - if (ss->ssl3.clientCertificate) { - CERT_DestroyCertificate(ss->ssl3.clientCertificate); - ss->ssl3.clientCertificate = NULL; - } - if (ss->ssl3.clientPrivateKey) { - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - ss->ssl3.clientPrivateKey = NULL; - } - if (ss->ssl3.clientCertChain != NULL) { - CERT_DestroyCertificateList(ss->ssl3.clientCertChain); - ss->ssl3.clientCertChain = NULL; - } - if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { - ss->ssl3.sendEmptyCert = PR_TRUE; - } else { - (void)SSL3_SendAlert(ss, alert_warning, no_certificate); - } - } - } else { - if (cert) { - CERT_DestroyCertificate(cert); - } - if (key) { - SECKEY_DestroyPrivateKey(key); - } - if (certChain) { - CERT_DestroyCertificateList(certChain); - } - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } - return rv; -} - -static SECStatus -ssl3_CheckFalseStart(sslSocket *ss) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(!ss->ssl3.hs.authCertificatePending); - PORT_Assert(!ss->ssl3.hs.canFalseStart); - - if (!ss->canFalseStartCallback) { - SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start", - SSL_GETPID(), ss->fd)); - } else { - PRBool maybeFalseStart; - SECStatus rv; - - /* An attacker can control the selected ciphersuite so we only wish to - * do False Start in the case that the selected ciphersuite is - * sufficiently strong that the attack can gain no advantage. - * Therefore we always require an 80-bit cipher. */ - ssl_GetSpecReadLock(ss); - maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10; - ssl_ReleaseSpecReadLock(ss); - - if (!maybeFalseStart) { - SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher", - SSL_GETPID(), ss->fd)); - } else { - PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == - ssl_preinfo_all); - rv = (ss->canFalseStartCallback)(ss->fd, - ss->canFalseStartCallbackData, - &ss->ssl3.hs.canFalseStart); - if (rv == SECSuccess) { - SSL_TRC(3, ("%d: SSL[%d]: false start callback returned %s", - SSL_GETPID(), ss->fd, - ss->ssl3.hs.canFalseStart ? "TRUE" - : "FALSE")); - } else { - SSL_TRC(3, ("%d: SSL[%d]: false start callback failed (%s)", - SSL_GETPID(), ss->fd, - PR_ErrorToName(PR_GetError()))); - } - return rv; - } - } - - ss->ssl3.hs.canFalseStart = PR_FALSE; - return SECSuccess; -} - -PRBool -ssl3_WaitingForServerSecondRound(sslSocket *ss) -{ - PRBool result; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - switch (ss->ssl3.hs.ws) { - case wait_new_session_ticket: - case wait_change_cipher: - case wait_finished: - result = PR_TRUE; - break; - default: - result = PR_FALSE; - break; - } - - return result; -} - -static SECStatus ssl3_SendClientSecondRound(sslSocket *ss); - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 Server Hello Done message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleServerHelloDone(sslSocket *ss) -{ - SECStatus rv; - SSL3WaitState ws = ss->ssl3.hs.ws; - - SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - /* Skipping CertificateRequest is always permitted. */ - if (ws != wait_hello_done && - ws != wait_cert_request) { - SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE); - return SECFailure; - } - - rv = ssl3_SendClientSecondRound(ss); - - return rv; -} - -/* Called from ssl3_HandleServerHelloDone and ssl3_AuthCertificateComplete. - * - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_SendClientSecondRound(sslSocket *ss) -{ - SECStatus rv; - PRBool sendClientCert; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - sendClientCert = !ss->ssl3.sendEmptyCert && - ss->ssl3.clientCertChain != NULL && - ss->ssl3.clientPrivateKey != NULL; - - if (!sendClientCert && - ss->ssl3.hs.hashType == handshake_hash_single && - ss->ssl3.hs.backupHash) { - /* Don't need the backup handshake hash. */ - PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE); - ss->ssl3.hs.backupHash = NULL; - } - - /* We must wait for the server's certificate to be authenticated before - * sending the client certificate in order to disclosing the client - * certificate to an attacker that does not have a valid cert for the - * domain we are connecting to. - * - * XXX: We should do the same for the NPN extension, but for that we - * need an option to give the application the ability to leak the NPN - * information to get better performance. - * - * During the initial handshake on a connection, we never send/receive - * application data until we have authenticated the server's certificate; - * i.e. we have fully authenticated the handshake before using the cipher - * specs agreed upon for that handshake. During a renegotiation, we may - * continue sending and receiving application data during the handshake - * interleaved with the handshake records. If we were to send the client's - * second round for a renegotiation before the server's certificate was - * authenticated, then the application data sent/received after this point - * would be using cipher spec that hadn't been authenticated. By waiting - * until the server's certificate has been authenticated during - * renegotiations, we ensure that renegotiations have the same property - * as initial handshakes; i.e. we have fully authenticated the handshake - * before using the cipher specs agreed upon for that handshake for - * application data. - */ - if (ss->ssl3.hs.restartTarget) { - PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget"); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - if (ss->ssl3.hs.authCertificatePending && - (sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) { - SSL_TRC(3, ("%d: SSL3[%p]: deferring ssl3_SendClientSecondRound because" - " certificate authentication is still pending.", - SSL_GETPID(), ss->fd)); - ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound; - return SECWouldBlock; - } - - ssl_GetXmitBufLock(ss); /*******************************/ - - if (ss->ssl3.sendEmptyCert) { - ss->ssl3.sendEmptyCert = PR_FALSE; - rv = ssl3_SendEmptyCertificate(ss); - /* Don't send verify */ - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } - } else if (sendClientCert) { - rv = ssl3_SendCertificate(ss); - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } - } - - rv = ssl3_SendClientKeyExchange(ss); - if (rv != SECSuccess) { - goto loser; /* err is set. */ - } - - if (sendClientCert) { - rv = ssl3_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey); - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - ss->ssl3.clientPrivateKey = NULL; - if (rv != SECSuccess) { - goto loser; /* err is set. */ - } - } - - rv = ssl3_SendChangeCipherSpecs(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - - /* This must be done after we've set ss->ssl3.cwSpec in - * ssl3_SendChangeCipherSpecs because SSL_GetChannelInfo uses information - * from cwSpec. This must be done before we call ssl3_CheckFalseStart - * because the false start callback (if any) may need the information from - * the functions that depend on this being set. - */ - ss->enoughFirstHsDone = PR_TRUE; - - if (!ss->firstHsDone) { - /* XXX: If the server's certificate hasn't been authenticated by this - * point, then we may be leaking this NPN message to an attacker. - */ - rv = ssl3_SendNextProto(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - } - - rv = ssl3_SendChannelIDEncryptedExtensions(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - - if (!ss->firstHsDone) { - if (ss->opt.enableFalseStart) { - if (!ss->ssl3.hs.authCertificatePending) { - /* When we fix bug 589047, we will need to know whether we are - * false starting before we try to flush the client second - * round to the network. With that in mind, we purposefully - * call ssl3_CheckFalseStart before calling ssl3_SendFinished, - * which includes a call to ssl3_FlushHandshake, so that - * no application develops a reliance on such flushing being - * done before its false start callback is called. - */ - ssl_ReleaseXmitBufLock(ss); - rv = ssl3_CheckFalseStart(ss); - ssl_GetXmitBufLock(ss); - if (rv != SECSuccess) { - goto loser; - } - } else { - /* The certificate authentication and the server's Finished - * message are racing each other. If the certificate - * authentication wins, then we will try to false start in - * ssl3_AuthCertificateComplete. - */ - SSL_TRC(3, ("%d: SSL3[%p]: deferring false start check because" - " certificate authentication is still pending.", - SSL_GETPID(), ss->fd)); - } - } - } - - rv = ssl3_SendFinished(ss, 0); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - - ssl_ReleaseXmitBufLock(ss); /*******************************/ - - if (!ss->ssl3.hs.isResuming && - ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { - /* If we are negotiating ChannelID on a full handshake then we record - * the handshake hashes in |sid| at this point. They will be needed in - * the event that we resume this session and use ChannelID on the - * resumption handshake. */ - SSL3Hashes hashes; - SECItem *originalHandshakeHash = - &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; - PORT_Assert(ss->sec.ci.sid->cached == never_cached); - - ssl_GetSpecReadLock(ss); - PORT_Assert(ss->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); - ssl_ReleaseSpecReadLock(ss); - if (rv != SECSuccess) { - return rv; - } - - PORT_Assert(originalHandshakeHash->len == 0); - originalHandshakeHash->data = PORT_Alloc(hashes.len); - if (!originalHandshakeHash->data) - return SECFailure; - originalHandshakeHash->len = hashes.len; - memcpy(originalHandshakeHash->data, hashes.u.raw, hashes.len); - } - - if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) - ss->ssl3.hs.ws = wait_new_session_ticket; - else - ss->ssl3.hs.ws = wait_change_cipher; - - PORT_Assert(ssl3_WaitingForServerSecondRound(ss)); - - return SECSuccess; - -loser: - ssl_ReleaseXmitBufLock(ss); - return rv; -} - -/* - * Routines used by servers - */ -static SECStatus -ssl3_SendHelloRequest(sslSocket *ss) -{ - SECStatus rv; - - SSL_TRC(3, ("%d: SSL3[%d]: send hello_request handshake", SSL_GETPID(), - ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - rv = ssl3_AppendHandshakeHeader(ss, hello_request, 0); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake */ - } - rv = ssl3_FlushHandshake(ss, 0); - if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ - } - ss->ssl3.hs.ws = wait_client_hello; - return SECSuccess; -} - -/* - * Called from: - * ssl3_HandleClientHello() - */ -static SECComparison -ssl3_ServerNameCompare(const SECItem *name1, const SECItem *name2) -{ - if (!name1 != !name2) { - return SECLessThan; - } - if (!name1) { - return SECEqual; - } - if (name1->type != name2->type) { - return SECLessThan; - } - return SECITEM_CompareItem(name1, name2); -} - -/* Sets memory error when returning NULL. - * Called from: - * ssl3_SendClientHello() - * ssl3_HandleServerHello() - * ssl3_HandleClientHello() - * ssl3_HandleV2ClientHello() - */ -sslSessionID * -ssl3_NewSessionID(sslSocket *ss, PRBool is_server) -{ - sslSessionID *sid; - - sid = PORT_ZNew(sslSessionID); - if (sid == NULL) - return sid; - - if (is_server) { - const SECItem *srvName; - SECStatus rv = SECSuccess; - - ssl_GetSpecReadLock(ss); /********************************/ - srvName = &ss->ssl3.prSpec->srvVirtName; - if (srvName->len && srvName->data) { - rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, srvName); - } - ssl_ReleaseSpecReadLock(ss); /************************************/ - if (rv != SECSuccess) { - PORT_Free(sid); - return NULL; - } - } - sid->peerID = (ss->peerID == NULL) ? NULL : PORT_Strdup(ss->peerID); - sid->urlSvrName = (ss->url == NULL) ? NULL : PORT_Strdup(ss->url); - sid->addr = ss->sec.ci.peer; - sid->port = ss->sec.ci.port; - sid->references = 1; - sid->cached = never_cached; - sid->version = ss->version; - - sid->u.ssl3.keys.resumable = PR_TRUE; - sid->u.ssl3.policy = SSL_ALLOWED; - sid->u.ssl3.clientWriteKey = NULL; - sid->u.ssl3.serverWriteKey = NULL; - sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE; - - if (is_server) { - SECStatus rv; - int pid = SSL_GETPID(); - - sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES; - sid->u.ssl3.sessionID[0] = (pid >> 8) & 0xff; - sid->u.ssl3.sessionID[1] = pid & 0xff; - rv = PK11_GenerateRandom(sid->u.ssl3.sessionID + 2, - SSL3_SESSIONID_BYTES - 2); - if (rv != SECSuccess) { - ssl_FreeSID(sid); - ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); - return NULL; - } - } - return sid; -} - -/* Called from: ssl3_HandleClientHello, ssl3_HandleV2ClientHello */ -static SECStatus -ssl3_SendServerHelloSequence(sslSocket *ss) -{ - const ssl3KEADef *kea_def; - SECStatus rv; - - SSL_TRC(3, ("%d: SSL3[%d]: begin send server_hello sequence", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - rv = ssl3_SendServerHello(ss); - if (rv != SECSuccess) { - return rv; /* err code is set. */ - } - rv = ssl3_SendCertificate(ss); - if (rv != SECSuccess) { - return rv; /* error code is set. */ - } - rv = ssl3_SendCertificateStatus(ss); - if (rv != SECSuccess) { - return rv; /* error code is set. */ - } - /* We have to do this after the call to ssl3_SendServerHello, - * because kea_def is set up by ssl3_SendServerHello(). - */ - kea_def = ss->ssl3.hs.kea_def; - ss->ssl3.hs.usedStepDownKey = PR_FALSE; - - if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) { - /* see if we can legally use the key in the cert. */ - unsigned int keyLen; /* bytes */ - - keyLen = PK11_GetPrivateModulusLen( - ss->serverCerts[kea_def->exchKeyType].SERVERKEY); - - if (keyLen > 0 && - keyLen * BPB <= kea_def->key_size_limit) { - /* XXX AND cert is not signing only!! */ - /* just fall through and use it. */ - } else if (ss->stepDownKeyPair != NULL) { - ss->ssl3.hs.usedStepDownKey = PR_TRUE; - rv = ssl3_SendServerKeyExchange(ss); - if (rv != SECSuccess) { - return rv; /* err code was set. */ - } - } else { -#ifndef HACKED_EXPORT_SERVER - PORT_SetError(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED); - return rv; -#endif - } - } else if (kea_def->ephemeral) { - rv = ssl3_SendServerKeyExchange(ss); - if (rv != SECSuccess) { - return rv; /* err code was set. */ - } - } - - if (ss->opt.requestCertificate) { - rv = ssl3_SendCertificateRequest(ss); - if (rv != SECSuccess) { - return rv; /* err code is set. */ - } - } - rv = ssl3_SendServerHelloDone(ss); - if (rv != SECSuccess) { - return rv; /* err code is set. */ - } - - ss->ssl3.hs.ws = (ss->opt.requestCertificate) ? wait_client_cert - : wait_client_key; - return SECSuccess; -} - -/* An empty TLS Renegotiation Info (RI) extension */ -static const PRUint8 emptyRIext[5] = { 0xff, 0x01, 0x00, 0x01, 0x00 }; - -static PRBool -ssl3_KEAAllowsSessionTicket(SSL3KeyExchangeAlgorithm kea) -{ - switch (kea) { - case kea_dhe_dss: - case kea_dhe_dss_export: - case kea_dh_dss_export: - case kea_dh_dss: - /* TODO: Fix session tickets for DSS. The server code rejects the - * session ticket received from the client. Bug 1174677 */ - return PR_FALSE; - default: - return PR_TRUE; - }; -} - -static void -ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid) -{ - PLArenaPool *arena; - ssl3CertNode *lastCert = NULL; - ssl3CertNode *certs = NULL; - int i; - - if (!sid->peerCertChain[0]) - return; - PORT_Assert(!ss->ssl3.peerCertArena); - PORT_Assert(!ss->ssl3.peerCertChain); - ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { - ssl3CertNode *c = PORT_ArenaNew(arena, ssl3CertNode); - c->cert = CERT_DupCertificate(sid->peerCertChain[i]); - c->next = NULL; - if (lastCert) { - lastCert->next = c; - } else { - certs = c; - } - lastCert = c; - } - ss->ssl3.peerCertChain = certs; -} - -static void -ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, sslSessionID *sid) -{ - int i = 0; - ssl3CertNode *c = certs; - for (; i < MAX_PEER_CERT_CHAIN_SIZE && c; i++, c = c->next) { - PORT_Assert(!sid->peerCertChain[i]); - sid->peerCertChain[i] = CERT_DupCertificate(c->cert); - } -} - -/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete - * ssl3 Client Hello message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - sslSessionID *sid = NULL; - PRInt32 tmp; - unsigned int i; - int j; - SECStatus rv; - int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; - SSL3AlertDescription desc = illegal_parameter; - SSL3AlertLevel level = alert_fatal; - SSL3ProtocolVersion version; - SECItem sidBytes = { siBuffer, NULL, 0 }; - SECItem cookieBytes = { siBuffer, NULL, 0 }; - SECItem suites = { siBuffer, NULL, 0 }; - SECItem comps = { siBuffer, NULL, 0 }; - PRBool haveSpecWriteLock = PR_FALSE; - PRBool haveXmitBufLock = PR_FALSE; - PRBool canOfferSessionTicket = PR_FALSE; - PRBool isTLS13 = PR_FALSE; - - SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.initialized); - ss->ssl3.hs.preliminaryInfo = 0; - - if (!ss->sec.isServer || - (ss->ssl3.hs.ws != wait_client_hello && - ss->ssl3.hs.ws != idle_handshake)) { - desc = unexpected_message; - errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO; - goto alert_loser; - } - if (ss->ssl3.hs.ws == idle_handshake) { - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - desc = unexpected_message; - errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; - goto alert_loser; - } - if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) { - desc = no_renegotiation; - level = alert_warning; - errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; - goto alert_loser; - } - } - - /* Get peer name of client */ - rv = ssl_GetPeerInfo(ss); - if (rv != SECSuccess) { - return rv; /* error code is set. */ - } - - /* Clearing the handshake pointers so that ssl_Do1stHandshake won't - * call ssl2_HandleMessage. - * - * The issue here is that TLS ordinarily starts out in - * ssl2_HandleV3HandshakeRecord() because of the backward-compatibility - * code paths. That function zeroes these next pointers. But with DTLS, - * we don't even try to do the v2 ClientHello so we skip that function - * and need to reset these values here. - */ - if (IS_DTLS(ss)) { - ss->nextHandshake = 0; - ss->securityHandshake = 0; - } - - /* We might be starting session renegotiation in which case we should - * clear previous state. - */ - PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData)); - ss->statelessResume = PR_FALSE; - - if (IS_DTLS(ss)) { - dtls_RehandshakeCleanup(ss); - } - - tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (tmp < 0) - goto loser; /* malformed, alert already sent */ - - /* Translate the version */ - if (IS_DTLS(ss)) { - ss->clientHelloVersion = version = - dtls_DTLSVersionToTLSVersion((SSL3ProtocolVersion)tmp); - } else { - ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp; - } - - rv = ssl3_NegotiateVersion(ss, version, PR_TRUE); - if (rv != SECSuccess) { - desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version - : handshake_failure; - errCode = SSL_ERROR_UNSUPPORTED_VERSION; - goto alert_loser; - } - isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; - - rv = ssl3_InitHandshakeHashes(ss); - if (rv != SECSuccess) { - desc = internal_error; - errCode = PORT_GetError(); - goto alert_loser; - } - - /* Generate the Server Random now so it is available - * when we process the ClientKeyShare in TLS 1.3 */ - rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random); - if (rv != SECSuccess) { - errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE; - goto loser; - } - - /* - * [draft-ietf-tls-tls13-11 Section 6.3.1.1]. - * TLS 1.3 server implementations which respond to a ClientHello with a - * client_version indicating TLS 1.2 or below MUST set the first eight - * bytes of their Random value to the bytes: - * - * 44 4F 57 4E 47 52 44 01 - * - * TLS 1.2 server implementations which respond to a ClientHello with a - * client_version indicating TLS 1.1 or below SHOULD set the first eight - * bytes of their Random value to the bytes: - * - * 44 4F 57 4E 47 52 44 00 - * - * TODO(ekr@rtfm.com): Note this change was not added in the SSLv2 - * compat processing code since that will most likely be removed before - * we ship the final version of TLS 1.3. - */ - if (ss->vrange.max > ss->version) { - switch (ss->vrange.max) { - case SSL_LIBRARY_VERSION_TLS_1_3: - PORT_Memcpy(ss->ssl3.hs.server_random.rand, - tls13_downgrade_random, - sizeof(tls13_downgrade_random)); - break; - case SSL_LIBRARY_VERSION_TLS_1_2: - PORT_Memcpy(ss->ssl3.hs.server_random.rand, - tls12_downgrade_random, - sizeof(tls12_downgrade_random)); - break; - default: - /* Do not change random. */ - break; - } - } - - /* grab the client random data. */ - rv = ssl3_ConsumeHandshake( - ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed */ - } - - /* grab the client's SID, if present. */ - rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed */ - } - - /* grab the client's cookie, if present. */ - if (IS_DTLS(ss)) { - rv = ssl3_ConsumeHandshakeVariable(ss, &cookieBytes, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed */ - } - } - - /* grab the list of cipher suites. */ - rv = ssl3_ConsumeHandshakeVariable(ss, &suites, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed */ - } - - /* If the ClientHello version is less than our maximum version, check for a - * TLS_FALLBACK_SCSV and reject the connection if found. */ - if (ss->vrange.max > ss->clientHelloVersion) { - for (i = 0; i + 1 < suites.len; i += 2) { - PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; - if (suite_i != TLS_FALLBACK_SCSV) - continue; - desc = inappropriate_fallback; - errCode = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; - goto alert_loser; - } - } - - /* grab the list of compression methods. */ - rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed */ - } - - /* TLS 1.3 requires that compression be empty */ - if (isTLS13) { - if (comps.len != 1 || comps.data[0] != ssl_compression_null) { - goto loser; - } - } - desc = handshake_failure; - - /* Handle TLS hello extensions for SSL3 & TLS. We do not know if - * we are restarting a previous session until extensions have been - * parsed, since we might have received a SessionTicket extension. - * Note: we allow extensions even when negotiating SSL3 for the sake - * of interoperability (and backwards compatibility). - */ - - if (length) { - /* Get length of hello extensions */ - PRInt32 extension_length; - extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (extension_length < 0) { - goto loser; /* alert already sent */ - } - if (extension_length != length) { - ssl3_DecodeError(ss); /* send alert */ - goto loser; - } - rv = ssl3_HandleHelloExtensions(ss, &b, &length, client_hello); - if (rv != SECSuccess) { - goto loser; /* malformed */ - } - } - if (!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - /* If we didn't receive an RI extension, look for the SCSV, - * and if found, treat it just like an empty RI extension - * by processing a local copy of an empty RI extension. - */ - for (i = 0; i + 1 < suites.len; i += 2) { - PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; - if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { - SSL3Opaque *b2 = (SSL3Opaque *)emptyRIext; - PRUint32 L2 = sizeof emptyRIext; - (void)ssl3_HandleHelloExtensions(ss, &b2, &L2, client_hello); - break; - } - } - } - if (ss->firstHsDone && - (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN || - ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) && - !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - desc = no_renegotiation; - level = alert_warning; - errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; - goto alert_loser; - } - if ((ss->opt.requireSafeNegotiation || - (ss->firstHsDone && ss->peerRequestedProtection)) && - !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - desc = handshake_failure; - errCode = SSL_ERROR_UNSAFE_NEGOTIATION; - goto alert_loser; - } - - /* We do stateful resumes only if either of the following - * conditions are satisfied: (1) the client does not support the - * session ticket extension, or (2) the client support the session - * ticket extension, but sent an empty ticket. - */ - if (!ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) || - ss->xtnData.emptySessionTicket) { - if (sidBytes.len > 0 && !ss->opt.noCache) { - SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x", - SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0], - ss->sec.ci.peer.pr_s6_addr32[1], - ss->sec.ci.peer.pr_s6_addr32[2], - ss->sec.ci.peer.pr_s6_addr32[3])); - if (ssl_sid_lookup) { - sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sidBytes.data, - sidBytes.len, ss->dbHandle); - } else { - errCode = SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED; - goto loser; - } - } - } else if (ss->statelessResume) { - /* Fill in the client's session ID if doing a stateless resume. - * (When doing stateless resumes, server echos client's SessionID.) - */ - sid = ss->sec.ci.sid; - PORT_Assert(sid != NULL); /* Should have already been filled in.*/ - - if (sidBytes.len > 0 && sidBytes.len <= SSL3_SESSIONID_BYTES) { - sid->u.ssl3.sessionIDLength = sidBytes.len; - PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, - sidBytes.len); - sid->u.ssl3.sessionIDLength = sidBytes.len; - } else { - sid->u.ssl3.sessionIDLength = 0; - } - ss->sec.ci.sid = NULL; - } - - /* We only send a session ticket extension if the client supports - * the extension and we are unable to do either a stateful or - * stateless resume. - * - * TODO: send a session ticket if performing a stateful - * resumption. (As per RFC4507, a server may issue a session - * ticket while doing a (stateless or stateful) session resume, - * but OpenSSL-0.9.8g does not accept session tickets while - * resuming.) - */ - if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && sid == NULL) { - canOfferSessionTicket = PR_TRUE; - } - - if (sid != NULL) { - /* We've found a session cache entry for this client. - * Now, if we're going to require a client-auth cert, - * and we don't already have this client's cert in the session cache, - * and this is the first handshake on this connection (not a redo), - * then drop this old cache entry and start a new session. - */ - if ((sid->peerCert == NULL) && ss->opt.requestCertificate && - ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) || - (ss->opt.requireCertificate == SSL_REQUIRE_NO_ERROR) || - ((ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE) && - !ss->firstHsDone))) { - - SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok); - if (ss->sec.uncache) - ss->sec.uncache(sid); - ssl_FreeSID(sid); - sid = NULL; - } - } - -#ifndef NSS_DISABLE_ECC - /* Disable any ECC cipher suites for which we have no cert. */ - ssl3_FilterECCipherSuitesByServerCerts(ss); -#endif - - if (IS_DTLS(ss)) { - ssl3_DisableNonDTLSSuites(ss); - } - -#ifdef PARANOID - /* Look for a matching cipher suite. */ - j = ssl3_config_match_init(ss); - if (j <= 0) { /* no ciphers are working/supported by PK11 */ - errCode = PORT_GetError(); /* error code is already set. */ - goto alert_loser; - } -#endif - - /* If we already have a session for this client, be sure to pick the - ** same cipher suite and compression method we picked before. - ** This is not a loop, despite appearances. - */ - if (sid) - do { - ssl3CipherSuiteCfg *suite; -#ifdef PARANOID - SSLVersionRange vrange = { ss->version, ss->version }; -#endif - - /* Check that the cached compression method is still enabled. */ - if (!compressionEnabled(ss, sid->u.ssl3.compression)) - break; - - /* Check that the cached compression method is in the client's list */ - for (i = 0; i < comps.len; i++) { - if (comps.data[i] == sid->u.ssl3.compression) - break; - } - if (i == comps.len) - break; - - suite = ss->cipherSuites; - /* Find the entry for the cipher suite used in the cached session. */ - for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) { - if (suite->cipher_suite == sid->u.ssl3.cipherSuite) - break; - } - PORT_Assert(j > 0); - if (j <= 0) - break; -#ifdef PARANOID - /* Double check that the cached cipher suite is still enabled, - * implemented, and allowed by policy. Might have been disabled. - * The product policy won't change during the process lifetime. - * Implemented ("isPresent") shouldn't change for servers. - */ - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) - break; -#else - if (!suite->enabled) - break; -#endif - /* Double check that the cached cipher suite is in the client's list */ - for (i = 0; i + 1 < suites.len; i += 2) { - PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; - if (suite_i == suite->cipher_suite) { - ss->ssl3.hs.cipher_suite = - suite->cipher_suite; - ss->ssl3.hs.suite_def = - ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); - ss->ssl3.hs.kea_def = - &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg]; - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite; - - /* Use the cached compression method. */ - ss->ssl3.hs.compression = - sid->u.ssl3.compression; - goto compression_found; - } - } - } while (0); - -/* START A NEW SESSION */ - -#ifndef PARANOID - /* Look for a matching cipher suite. */ - j = ssl3_config_match_init(ss); - if (j <= 0) { /* no ciphers are working/supported by PK11 */ - errCode = PORT_GetError(); /* error code is already set. */ - goto alert_loser; - } -#endif - - /* Select a cipher suite. - ** - ** NOTE: This suite selection algorithm should be the same as the one in - ** ssl3_HandleV2ClientHello(). - ** - ** If TLS 1.0 is enabled, we could handle the case where the client - ** offered TLS 1.1 but offered only export cipher suites by choosing TLS - ** 1.0 and selecting one of those export cipher suites. However, a secure - ** TLS 1.1 client should not have export cipher suites enabled at all, - ** and a TLS 1.1 client should definitely not be offering *only* export - ** cipher suites. Therefore, we refuse to negotiate export cipher suites - ** with any client that indicates support for TLS 1.1 or higher when we - ** (the server) have TLS 1.1 support enabled. - */ - for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; - SSLVersionRange vrange = { ss->version, ss->version }; - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) { - continue; - } - for (i = 0; i + 1 < suites.len; i += 2) { - PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; - if (suite_i == suite->cipher_suite) { - ss->ssl3.hs.cipher_suite = suite->cipher_suite; - ss->ssl3.hs.suite_def = - ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); - ss->ssl3.hs.kea_def = - &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg]; - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite; - goto suite_found; - } - } - } - errCode = SSL_ERROR_NO_CYPHER_OVERLAP; - goto alert_loser; - -suite_found: - if (canOfferSessionTicket) - canOfferSessionTicket = ssl3_KEAAllowsSessionTicket( - ss->ssl3.hs.suite_def->key_exchange_alg); - - if (canOfferSessionTicket) { - ssl3_RegisterServerHelloExtensionSender(ss, - ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn); - } - - /* Select a compression algorithm. */ - for (i = 0; i < comps.len; i++) { - if (!compressionEnabled(ss, comps.data[i])) - continue; - for (j = 0; j < compressionMethodsCount; j++) { - if (comps.data[i] == compressions[j]) { - ss->ssl3.hs.compression = - (SSLCompressionMethod)compressions[j]; - goto compression_found; - } - } - } - errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP; - /* null compression must be supported */ - goto alert_loser; - -compression_found: - suites.data = NULL; - comps.data = NULL; - - ss->sec.send = ssl3_SendApplicationData; - - /* If there are any failures while processing the old sid, - * we don't consider them to be errors. Instead, We just behave - * as if the client had sent us no sid to begin with, and make a new one. - * The exception here is attempts to resume extended_master_secret - * sessions without the extension, which causes an alert. - */ - if (sid != NULL) - do { - ssl3CipherSpec *pwSpec; - SECItem wrappedMS; /* wrapped key */ - - if (sid->version != ss->version || - sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite || - sid->u.ssl3.compression != ss->ssl3.hs.compression) { - break; /* not an error */ - } - - /* [draft-ietf-tls-session-hash-06; Section 5.3] - * o If the original session did not use the "extended_master_secret" - * extension but the new ClientHello contains the extension, then the - * server MUST NOT perform the abbreviated handshake. Instead, it - * SHOULD continue with a full handshake (as described in - * Section 5.2) to negotiate a new session. - * - * o If the original session used the "extended_master_secret" - * extension but the new ClientHello does not contain the extension, - * the server MUST abort the abbreviated handshake. - */ - if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) { - if (!sid->u.ssl3.keys.extendedMasterSecretUsed) { - break; /* not an error */ - } - } else { - if (sid->u.ssl3.keys.extendedMasterSecretUsed) { - /* Note: we do not destroy the session */ - desc = handshake_failure; - errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET; - goto alert_loser; - } - } - - if (ss->sec.ci.sid) { - if (ss->sec.uncache) - ss->sec.uncache(ss->sec.ci.sid); - PORT_Assert(ss->sec.ci.sid != sid); /* should be impossible, but ... */ - if (ss->sec.ci.sid != sid) { - ssl_FreeSID(ss->sec.ci.sid); - } - ss->sec.ci.sid = NULL; - } - /* we need to resurrect the master secret.... */ - - ssl_GetSpecWriteLock(ss); - haveSpecWriteLock = PR_TRUE; - pwSpec = ss->ssl3.pwSpec; - if (sid->u.ssl3.keys.msIsWrapped) { - PK11SymKey *wrapKey; /* wrapping key */ - CK_FLAGS keyFlags = 0; -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - /* we cannot restart a non-bypass session in a - ** bypass socket. - */ - break; - } -#endif - - wrapKey = getWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType, - sid->u.ssl3.masterWrapMech, - ss->pkcs11PinArg); - if (!wrapKey) { - /* we have a SID cache entry, but no wrapping key for it??? */ - break; - } - - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - keyFlags = - CKF_SIGN | CKF_VERIFY; - } - - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - - /* unwrap the master secret. */ - pwSpec->master_secret = - PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, - NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, - CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); - PK11_FreeSymKey(wrapKey); - if (pwSpec->master_secret == NULL) { - break; /* not an error */ - } -#ifndef NO_PKCS11_BYPASS - } else if (ss->opt.bypassPKCS11) { - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len); - pwSpec->msItem.data = pwSpec->raw_master_secret; - pwSpec->msItem.len = wrappedMS.len; -#endif - } else { - /* We CAN restart a bypass session in a non-bypass socket. */ - /* need to import the raw master secret to session object */ - PK11SlotInfo *slot; - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - slot = PK11_GetInternalSlot(); - pwSpec->master_secret = - PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, - PK11_OriginUnwrap, CKA_ENCRYPT, &wrappedMS, - NULL); - PK11_FreeSlot(slot); - if (pwSpec->master_secret == NULL) { - break; /* not an error */ - } - } - ss->sec.ci.sid = sid; - if (sid->peerCert != NULL) { - ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); - ssl3_CopyPeerCertsFromSID(ss, sid); - } - - /* - * Old SID passed all tests, so resume this old session. - * - * XXX make sure compression still matches - */ - SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_hits); - if (ss->statelessResume) - SSL_AtomicIncrementLong(&ssl3stats.hch_sid_stateless_resumes); - ss->ssl3.hs.isResuming = PR_TRUE; - - ss->sec.authAlgorithm = sid->authAlgorithm; - ss->sec.authKeyBits = sid->authKeyBits; - ss->sec.keaType = sid->keaType; - ss->sec.keaKeyBits = sid->keaKeyBits; - - /* server sids don't remember the server cert we previously sent, - ** but they do remember the kea type we originally used, so we - ** can locate it again, provided that the current ssl socket - ** has had its server certs configured the same as the previous one. - */ - ss->sec.localCert = - CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert); - - /* Copy cached name in to pending spec */ - if (sid != NULL && - sid->version > SSL_LIBRARY_VERSION_3_0 && - sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) { - /* Set server name from sid */ - SECItem *sidName = &sid->u.ssl3.srvName; - SECItem *pwsName = &ss->ssl3.pwSpec->srvVirtName; - if (pwsName->data) { - SECITEM_FreeItem(pwsName, PR_FALSE); - } - rv = SECITEM_CopyItem(NULL, pwsName, sidName); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - desc = internal_error; - goto alert_loser; - } - } - - /* Clean up sni name array */ - if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn) && - ss->xtnData.sniNameArr) { - PORT_Free(ss->xtnData.sniNameArr); - ss->xtnData.sniNameArr = NULL; - ss->xtnData.sniNameArrSize = 0; - } - - ssl_GetXmitBufLock(ss); - haveXmitBufLock = PR_TRUE; - - rv = ssl3_SendServerHello(ss); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } - - /* NULL value for PMS because we are re-using the old MS */ - rv = ssl3_InitPendingCipherSpec(ss, NULL); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - - rv = ssl3_SendChangeCipherSpecs(ss); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - rv = ssl3_SendFinished(ss, 0); - ss->ssl3.hs.ws = wait_change_cipher; - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - - if (haveXmitBufLock) { - ssl_ReleaseXmitBufLock(ss); - haveXmitBufLock = PR_FALSE; - } - - return SECSuccess; - } while (0); - - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } - - if (sid) { /* we had a sid, but it's no longer valid, free it */ - SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok); - if (ss->sec.uncache) - ss->sec.uncache(sid); - ssl_FreeSID(sid); - sid = NULL; - } - SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_misses); - - if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) { - int ret = 0; - if (ss->sniSocketConfig) - do { /* not a loop */ - PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == - ssl_preinfo_all); - - ret = SSL_SNI_SEND_ALERT; - /* If extension is negotiated, the len of names should > 0. */ - if (ss->xtnData.sniNameArrSize) { - /* Calling client callback to reconfigure the socket. */ - ret = (SECStatus)(*ss->sniSocketConfig)(ss->fd, - ss->xtnData.sniNameArr, - ss->xtnData.sniNameArrSize, - ss->sniSocketConfigArg); - } - if (ret <= SSL_SNI_SEND_ALERT) { - /* Application does not know the name or was not able to - * properly reconfigure the socket. */ - errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; - desc = unrecognized_name; - break; - } else if (ret == SSL_SNI_CURRENT_CONFIG_IS_USED) { - SECStatus rv = SECSuccess; - SECItem *cwsName, *pwsName; - - ssl_GetSpecWriteLock(ss); /*******************************/ - pwsName = &ss->ssl3.pwSpec->srvVirtName; - cwsName = &ss->ssl3.cwSpec->srvVirtName; -#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS - /* not allow name change on the 2d HS */ - if (ss->firstHsDone) { - if (ssl3_ServerNameCompare(pwsName, cwsName)) { - ssl_ReleaseSpecWriteLock(ss); /******************/ - errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; - desc = handshake_failure; - ret = SSL_SNI_SEND_ALERT; - break; - } - } -#endif - if (pwsName->data) { - SECITEM_FreeItem(pwsName, PR_FALSE); - } - if (cwsName->data) { - rv = SECITEM_CopyItem(NULL, pwsName, cwsName); - } - ssl_ReleaseSpecWriteLock(ss); /**************************/ - if (rv != SECSuccess) { - errCode = SSL_ERROR_INTERNAL_ERROR_ALERT; - desc = internal_error; - ret = SSL_SNI_SEND_ALERT; - break; - } - } else if ((unsigned int)ret < ss->xtnData.sniNameArrSize) { - /* Application has configured new socket info. Lets check it - * and save the name. */ - SECStatus rv; - SECItem *name = &ss->xtnData.sniNameArr[ret]; - int configedCiphers; - SECItem *pwsName; - - /* get rid of the old name and save the newly picked. */ - /* This code is protected by ssl3HandshakeLock. */ - ssl_GetSpecWriteLock(ss); /*******************************/ -#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS - /* not allow name change on the 2d HS */ - if (ss->firstHsDone) { - SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName; - if (ssl3_ServerNameCompare(name, cwsName)) { - ssl_ReleaseSpecWriteLock(ss); /******************/ - errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; - desc = handshake_failure; - ret = SSL_SNI_SEND_ALERT; - break; - } - } -#endif - pwsName = &ss->ssl3.pwSpec->srvVirtName; - if (pwsName->data) { - SECITEM_FreeItem(pwsName, PR_FALSE); - } - rv = SECITEM_CopyItem(NULL, pwsName, name); - ssl_ReleaseSpecWriteLock(ss); /***************************/ - if (rv != SECSuccess) { - errCode = SSL_ERROR_INTERNAL_ERROR_ALERT; - desc = internal_error; - ret = SSL_SNI_SEND_ALERT; - break; - } - configedCiphers = ssl3_config_match_init(ss); - if (configedCiphers <= 0) { - /* no ciphers are working/supported */ - errCode = PORT_GetError(); - desc = handshake_failure; - ret = SSL_SNI_SEND_ALERT; - break; - } - /* Need to tell the client that application has picked - * the name from the offered list and reconfigured the socket. - */ - ssl3_RegisterServerHelloExtensionSender(ss, ssl_server_name_xtn, - ssl3_SendServerNameXtn); - } else { - /* Callback returned index outside of the boundary. */ - PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize); - errCode = SSL_ERROR_INTERNAL_ERROR_ALERT; - desc = internal_error; - ret = SSL_SNI_SEND_ALERT; - break; - } - } while (0); - /* Free sniNameArr. The data that each SECItem in the array - * points into is the data from the input buffer "b". It will - * not be available outside the scope of this or it's child - * functions.*/ - if (ss->xtnData.sniNameArr) { - PORT_Free(ss->xtnData.sniNameArr); - ss->xtnData.sniNameArr = NULL; - ss->xtnData.sniNameArrSize = 0; - } - if (ret <= SSL_SNI_SEND_ALERT) { - /* desc and errCode should be set. */ - goto alert_loser; - } - } -#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS - else if (ss->firstHsDone) { - /* Check that we don't have the name is current spec - * if this extension was not negotiated on the 2d hs. */ - PRBool passed = PR_TRUE; - ssl_GetSpecReadLock(ss); /*******************************/ - if (ss->ssl3.cwSpec->srvVirtName.data) { - passed = PR_FALSE; - } - ssl_ReleaseSpecReadLock(ss); /***************************/ - if (!passed) { - errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; - desc = handshake_failure; - goto alert_loser; - } - } -#endif - - /* If this is TLS 1.3 we are expecting a ClientKeyShare - * extension. Missing/absent extension cause failure - * below. */ - if (isTLS13) { - rv = tls13_HandleClientKeyShare(ss); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto alert_loser; - } - } - - sid = ssl3_NewSessionID(ss, PR_TRUE); - if (sid == NULL) { - errCode = PORT_GetError(); - goto loser; /* memory error is set. */ - } - ss->sec.ci.sid = sid; - - sid->u.ssl3.keys.extendedMasterSecretUsed = - ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn); - ss->ssl3.hs.isResuming = PR_FALSE; - - ssl_GetXmitBufLock(ss); - if (isTLS13) { - rv = tls13_SendServerHelloSequence(ss); - } else { - rv = ssl3_SendServerHelloSequence(ss); - } - ssl_ReleaseXmitBufLock(ss); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - desc = handshake_failure; - goto alert_loser; - } - - if (haveXmitBufLock) { - ssl_ReleaseXmitBufLock(ss); - haveXmitBufLock = PR_FALSE; - } - - return SECSuccess; - -alert_loser: - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } - (void)SSL3_SendAlert(ss, level, desc); -/* FALLTHRU */ -loser: - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } - - if (haveXmitBufLock) { - ssl_ReleaseXmitBufLock(ss); - haveXmitBufLock = PR_FALSE; - } - - PORT_SetError(errCode); - return SECFailure; -} - -/* - * ssl3_HandleV2ClientHello is used when a V2 formatted hello comes - * in asking to use the V3 handshake. - * Called from ssl2_HandleClientHelloMessage() in sslcon.c - */ -SECStatus -ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) -{ - sslSessionID *sid = NULL; - unsigned char *suites; - unsigned char *random; - SSL3ProtocolVersion version; - SECStatus rv; - int i; - int j; - int sid_length; - int suite_length; - int rand_length; - int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; - SSL3AlertDescription desc = handshake_failure; - - SSL_TRC(3, ("%d: SSL3[%d]: handle v2 client_hello", SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - ssl_GetSSL3HandshakeLock(ss); - - PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData)); - - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; /* ssl3_InitState has set the error code. */ - } - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; - } - - if (ss->ssl3.hs.ws != wait_client_hello) { - desc = unexpected_message; - errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO; - goto loser; /* alert_loser */ - } - - version = (buffer[1] << 8) | buffer[2]; - suite_length = (buffer[3] << 8) | buffer[4]; - sid_length = (buffer[5] << 8) | buffer[6]; - rand_length = (buffer[7] << 8) | buffer[8]; - ss->clientHelloVersion = version; - - if (version >= SSL_LIBRARY_VERSION_TLS_1_3) { - /* [draft-ietf-tls-tls-11; C.3] forbids sending a TLS 1.3 - * ClientHello using the backwards-compatible format. */ - desc = illegal_parameter; - errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; - goto loser; - } - - rv = ssl3_NegotiateVersion(ss, version, PR_TRUE); - if (rv != SECSuccess) { - /* send back which ever alert client will understand. */ - desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version - : handshake_failure; - errCode = SSL_ERROR_UNSUPPORTED_VERSION; - goto alert_loser; - } - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; - - rv = ssl3_InitHandshakeHashes(ss); - if (rv != SECSuccess) { - desc = internal_error; - errCode = PORT_GetError(); - goto alert_loser; - } - - /* if we get a non-zero SID, just ignore it. */ - if (length != - SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + rand_length) { - SSL_DBG(("%d: SSL3[%d]: bad v2 client hello message, len=%d should=%d", - SSL_GETPID(), ss->fd, length, - SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + - rand_length)); - goto loser; /* malformed */ /* alert_loser */ - } - - suites = buffer + SSL_HL_CLIENT_HELLO_HBYTES; - random = suites + suite_length + sid_length; - - if (rand_length < SSL_MIN_CHALLENGE_BYTES || - rand_length > SSL_MAX_CHALLENGE_BYTES) { - goto loser; /* malformed */ /* alert_loser */ - } - - PORT_Assert(SSL_MAX_CHALLENGE_BYTES == SSL3_RANDOM_LENGTH); - - PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH); - PORT_Memcpy( - &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length], - random, rand_length); - - PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0], - SSL3_RANDOM_LENGTH)); -#ifndef NSS_DISABLE_ECC - /* Disable any ECC cipher suites for which we have no cert. */ - ssl3_FilterECCipherSuitesByServerCerts(ss); -#endif - i = ssl3_config_match_init(ss); - if (i <= 0) { - errCode = PORT_GetError(); /* error code is already set. */ - goto alert_loser; - } - - /* Select a cipher suite. - ** - ** NOTE: This suite selection algorithm should be the same as the one in - ** ssl3_HandleClientHello(). - ** - ** See the comments about export cipher suites in ssl3_HandleClientHello(). - */ - for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; - SSLVersionRange vrange = { ss->version, ss->version }; - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) { - continue; - } - for (i = 0; i + 2 < suite_length; i += 3) { - PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2]; - if (suite_i == suite->cipher_suite) { - ss->ssl3.hs.cipher_suite = suite->cipher_suite; - ss->ssl3.hs.suite_def = - ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); - ss->ssl3.hs.kea_def = - &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg]; - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite; - goto suite_found; - } - } - } - errCode = SSL_ERROR_NO_CYPHER_OVERLAP; - goto alert_loser; - -suite_found: - - /* Look for the SCSV, and if found, treat it just like an empty RI - * extension by processing a local copy of an empty RI extension. - */ - for (i = 0; i + 2 < suite_length; i += 3) { - PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2]; - if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { - SSL3Opaque *b2 = (SSL3Opaque *)emptyRIext; - PRUint32 L2 = sizeof emptyRIext; - (void)ssl3_HandleHelloExtensions(ss, &b2, &L2, client_hello); - break; - } - } - - if (ss->opt.requireSafeNegotiation && - !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - desc = handshake_failure; - errCode = SSL_ERROR_UNSAFE_NEGOTIATION; - goto alert_loser; - } - - ss->ssl3.hs.compression = ssl_compression_null; - ss->sec.send = ssl3_SendApplicationData; - - /* we don't even search for a cache hit here. It's just a miss. */ - SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_misses); - sid = ssl3_NewSessionID(ss, PR_TRUE); - if (sid == NULL) { - errCode = PORT_GetError(); - goto loser; /* memory error is set. */ - } - ss->sec.ci.sid = sid; - /* do not worry about memory leak of sid since it now belongs to ci */ - - /* We have to update the handshake hashes before we can send stuff */ - rv = ssl3_UpdateHandshakeHashes(ss, buffer, length); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - - ssl_GetXmitBufLock(ss); - rv = ssl3_SendServerHelloSequence(ss); - ssl_ReleaseXmitBufLock(ss); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - - /* XXX_1 The call stack to here is: - * ssl_Do1stHandshake -> ssl2_HandleClientHelloMessage -> here. - * ssl2_HandleClientHelloMessage returns whatever we return here. - * ssl_Do1stHandshake will continue looping if it gets back either - * SECSuccess or SECWouldBlock. - * SECSuccess is preferable here. See XXX_1 in sslgathr.c. - */ - ssl_ReleaseSSL3HandshakeLock(ss); - return SECSuccess; - -alert_loser: - SSL3_SendAlert(ss, alert_fatal, desc); -loser: - ssl_ReleaseSSL3HandshakeLock(ss); - PORT_SetError(errCode); - return SECFailure; -} - -/* The negotiated version number has been already placed in ss->version. -** -** Called from: ssl3_HandleClientHello (resuming session), -** ssl3_SendServerHelloSequence <- ssl3_HandleClientHello (new session), -** ssl3_SendServerHelloSequence <- ssl3_HandleV2ClientHello (new session) -*/ -SECStatus -ssl3_SendServerHello(sslSocket *ss) -{ - sslSessionID *sid; - SECStatus rv; - PRUint32 maxBytes = 65535; - PRUint32 length; - PRInt32 extensions_len = 0; - SSL3ProtocolVersion version; - - SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), - ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (!IS_DTLS(ss)) { - PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0)); - - if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return SECFailure; - } - } else { - PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_DTLS_1_0)); - - if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_DTLS_1_0)) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return SECFailure; - } - } - - sid = ss->sec.ci.sid; - - extensions_len = ssl3_CallHelloExtensionSenders( - ss, PR_FALSE, maxBytes, &ss->xtnData.serverHelloSenders[0]); - if (extensions_len > 0) - extensions_len += 2; /* Add sizeof total extension length */ - - /* TLS 1.3 doesn't use the session_id or compression_method - * fields in the ServerHello. */ - length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH; - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - length += 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength); - } - length += sizeof(ssl3CipherSuite); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - length += 1; /* Compression */ - } - length += extensions_len; - - rv = ssl3_AppendHandshakeHeader(ss, server_hello, length); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - - if (IS_DTLS(ss)) { - version = dtls_TLSVersionToDTLSVersion(ss->version); - } else { - version = ss->version; - } - - rv = ssl3_AppendHandshakeNumber(ss, version, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - /* Random already generated in ssl3_HandleClientHello */ - rv = ssl3_AppendHandshake( - ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - if (sid) { - rv = ssl3_AppendHandshakeVariable( - ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1); - } else { - rv = ssl3_AppendHandshakeNumber(ss, 0, 1); - } - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - if (extensions_len) { - PRInt32 sent_len; - - extensions_len -= 2; - rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); - if (rv != SECSuccess) - return rv; /* err set by ssl3_AppendHandshakeNumber */ - sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len, - &ss->xtnData.serverHelloSenders[0]); - PORT_Assert(sent_len == extensions_len); - if (sent_len != extensions_len) { - if (sent_len >= 0) - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - } - rv = ssl3_SetupPendingCipherSpec(ss); - if (rv != SECSuccess) { - return rv; /* err set by ssl3_SetupPendingCipherSpec */ - } - - return SECSuccess; -} - -static SECStatus -ssl3_PickSignatureHashAlgorithm(sslSocket *ss, - SSLSignatureAndHashAlg *out); - -static SECStatus -ssl3_SendDHServerKeyExchange(sslSocket *ss) -{ - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; - SECStatus rv = SECFailure; - int length; - PRBool isTLS; - SECItem signed_hash = { siBuffer, NULL, 0 }; - SSL3Hashes hashes; - SSLSignatureAndHashAlg sigAndHash; - SECKEYDHParams dhParam; - - ssl3KeyPair *keyPair = NULL; - SECKEYPublicKey *pubKey = NULL; /* Ephemeral DH key */ - SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */ - int certIndex = -1; - - if (kea_def->kea != kea_dhe_dss && kea_def->kea != kea_dhe_rsa) { - /* TODO: Support DH_anon. It might be sufficient to drop the signature. - See bug 1170510. */ - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - - dhParam.prime.data = ss->dheParams->prime.data; - dhParam.prime.len = ss->dheParams->prime.len; - dhParam.base.data = ss->dheParams->base.data; - dhParam.base.len = ss->dheParams->base.len; - - PRINT_BUF(60, (NULL, "Server DH p", dhParam.prime.data, - dhParam.prime.len)); - PRINT_BUF(60, (NULL, "Server DH g", dhParam.base.data, - dhParam.base.len)); - - /* Generate ephemeral DH keypair */ - privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL); - if (!privKey || !pubKey) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - goto loser; - } - - keyPair = ssl3_NewKeyPair(privKey, pubKey); - if (!keyPair) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - goto loser; - } - - PRINT_BUF(50, (ss, "DH public value:", - pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len)); - - if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - goto loser; - } - - rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, - pubKey->u.dh.prime, - pubKey->u.dh.base, - pubKey->u.dh.publicValue, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - - /* It has been suggested to test kea_def->signKeyType instead, and to use - * ssl_auth_* instead. Investigate what to do. See bug 102794. */ - if (kea_def->kea == kea_dhe_rsa) - certIndex = ssl_kea_rsa; - else - certIndex = ssl_kea_dh; - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY, - &signed_hash, isTLS); - if (rv != SECSuccess) { - goto loser; /* ssl3_SignHashes has set err. */ - } - if (signed_hash.data == NULL) { - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - length = 2 + pubKey->u.dh.prime.len + - 2 + pubKey->u.dh.base.len + - 2 + pubKey->u.dh.publicValue.len + - 2 + signed_hash.len; - - if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - length += 2; - } - - rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.prime.data, - pubKey->u.dh.prime.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.base.data, - pubKey->u.dh.base.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - } - - rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, - signed_hash.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - PORT_Free(signed_hash.data); - ss->dheKeyPair = keyPair; - return SECSuccess; - -loser: - if (signed_hash.data) - PORT_Free(signed_hash.data); - if (privKey) - SECKEY_DestroyPrivateKey(privKey); - if (pubKey) - SECKEY_DestroyPublicKey(pubKey); - return SECFailure; -} - -/* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing - * elements of the handshake. (The negotiated cipher suite determines the - * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always - * used. With TLS 1.2, a client may advertise its support for signature and - * hash combinations. */ -static SECStatus -ssl3_PickSignatureHashAlgorithm(sslSocket *ss, - SSLSignatureAndHashAlg *out) -{ - PRUint32 policy; - unsigned int i, j; - - out->sigAlg = ss->ssl3.hs.kea_def->signKeyType; - - if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_1) { - /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and - * prior. */ - out->hashAlg = ssl_hash_none; - return SECSuccess; - } - - if (ss->ssl3.hs.numClientSigAndHash == 0) { - /* If the client didn't provide any signature_algorithms extension then - * we can assume that they support SHA-1: - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ - out->hashAlg = ssl_hash_sha1; - return SECSuccess; - } - - /* Here we look for the first server preference that the client has - * indicated support for in their signature_algorithms extension. */ - for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) { - const SSLSignatureAndHashAlg *serverPref = - &ss->ssl3.signatureAlgorithms[i]; - SECOidTag hashOID; - if (serverPref->sigAlg != out->sigAlg) { - continue; - } - hashOID = ssl3_TLSHashAlgorithmToOID(serverPref->hashAlg); - if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) && - !(policy & NSS_USE_ALG_IN_SSL_KX)) { - /* we ignore hashes we don't support */ - continue; - } - for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) { - const SSLSignatureAndHashAlg *clientPref = - &ss->ssl3.hs.clientSigAndHash[j]; - if (clientPref->hashAlg == serverPref->hashAlg && - clientPref->sigAlg == out->sigAlg) { - out->hashAlg = serverPref->hashAlg; - return SECSuccess; - } - } - } - - PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); - return SECFailure; -} - -static SECStatus -ssl3_SendServerKeyExchange(sslSocket *ss) -{ - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; - SECStatus rv = SECFailure; - int length; - PRBool isTLS; - SECItem signed_hash = { siBuffer, NULL, 0 }; - SSL3Hashes hashes; - SECKEYPublicKey *sdPub; /* public key for step-down */ - SSLSignatureAndHashAlg sigAndHash; - - SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) { - return SECFailure; - } - - switch (kea_def->exchKeyType) { - case kt_rsa: - /* Perform SSL Step-Down here. */ - sdPub = ss->stepDownKeyPair->pubKey; - PORT_Assert(sdPub != NULL); - if (!sdPub) { - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, - sdPub->u.rsa.modulus, - sdPub->u.rsa.publicExponent, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return rv; - } - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].SERVERKEY, - &signed_hash, isTLS); - if (rv != SECSuccess) { - goto loser; /* ssl3_SignHashes has set err. */ - } - if (signed_hash.data == NULL) { - /* how can this happen and rv == SECSuccess ?? */ - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - length = 2 + sdPub->u.rsa.modulus.len + - 2 + sdPub->u.rsa.publicExponent.len + - 2 + signed_hash.len; - - if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - length += 2; - } - - rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, sdPub->u.rsa.modulus.data, - sdPub->u.rsa.modulus.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable( - ss, sdPub->u.rsa.publicExponent.data, - sdPub->u.rsa.publicExponent.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - } - - rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, - signed_hash.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - PORT_Free(signed_hash.data); - return SECSuccess; - - case ssl_kea_dh: { - rv = ssl3_SendDHServerKeyExchange(ss); - return rv; - } - -#ifndef NSS_DISABLE_ECC - case kt_ecdh: { - rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash); - return rv; - } -#endif /* NSS_DISABLE_ECC */ - - case kt_null: - default: - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); - break; - } -loser: - if (signed_hash.data != NULL) - PORT_Free(signed_hash.data); - return SECFailure; -} - -SECStatus -ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf, - unsigned maxLen, PRUint32 *len) -{ - unsigned int i; - - PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2); - if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - *len = 0; - for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) { - const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i]; - /* Note that we don't support a handshake hash with anything other than - * SHA-256, so asking for a signature from clients for something else - * would be inviting disaster. */ - if (alg->hashAlg == ssl_hash_sha256) { - buf[(*len)++] = (PRUint8)alg->hashAlg; - buf[(*len)++] = (PRUint8)alg->sigAlg; - } - } - - if (*len == 0) { - PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); - return SECFailure; - } - return SECSuccess; -} - -void -ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calen, SECItem **names, - int *nnames) -{ - SECItem *name; - CERTDistNames *ca_list; - int i; - - *calen = 0; - *names = NULL; - *nnames = 0; - - /* ssl3.ca_list is initialized to NULL, and never changed. */ - ca_list = ss->ssl3.ca_list; - if (!ca_list) { - ca_list = ssl3_server_ca_list; - } - - if (ca_list != NULL) { - *names = ca_list->names; - *nnames = ca_list->nnames; - } - - for (i = 0, name = *names; i < *nnames; i++, name++) { - *calen += 2 + name->len; - } -} - -static SECStatus -ssl3_SendCertificateRequest(sslSocket *ss) -{ - PRBool isTLS12; - const PRUint8 *certTypes; - SECStatus rv; - int length; - SECItem *names; - int calen; - int nnames; - SECItem *name; - int i; - int certTypesLength; - PRUint8 sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2]; - unsigned int sigAlgsLength = 0; - - SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames); - certTypes = certificate_types; - certTypesLength = sizeof certificate_types; - - length = 1 + certTypesLength + 2 + calen; - if (isTLS12) { - rv = ssl3_EncodeCertificateRequestSigAlgs(ss, sigAlgs, sizeof(sigAlgs), - &sigAlgsLength); - if (rv != SECSuccess) { - return rv; - } - length += 2 + sigAlgsLength; - } - - rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - rv = ssl3_AppendHandshakeVariable(ss, certTypes, certTypesLength, 1); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - if (isTLS12) { - rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - rv = ssl3_AppendHandshakeNumber(ss, calen, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - for (i = 0, name = names; i < nnames; i++, name++) { - rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - - return SECSuccess; -} - -static SECStatus -ssl3_SendServerHelloDone(sslSocket *ss) -{ - SECStatus rv; - - SSL_TRC(3, ("%d: SSL3[%d]: send server_hello_done handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - rv = ssl3_AppendHandshakeHeader(ss, server_hello_done, 0); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - rv = ssl3_FlushHandshake(ss, 0); - if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ - } - return SECSuccess; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 Certificate Verify message - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, - SSL3Hashes *hashes) -{ - SECItem signed_hash = { siBuffer, NULL, 0 }; - SECStatus rv; - int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY; - SSL3AlertDescription desc = handshake_failure; - PRBool isTLS, isTLS12; - SSLSignatureAndHashAlg sigAndHash; - - SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - if (ss->ssl3.hs.ws != wait_cert_verify) { - desc = unexpected_message; - errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY; - goto alert_loser; - } - - if (!hashes) { - PORT_Assert(0); - desc = internal_error; - errCode = SEC_ERROR_LIBRARY_FAILURE; - goto alert_loser; - } - - if (isTLS12) { - rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, - &sigAndHash); - if (rv != SECSuccess) { - goto loser; /* malformed or unsupported. */ - } - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( - ss, &sigAndHash, ss->sec.peerCert); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - desc = decrypt_error; - goto alert_loser; - } - - /* We only support CertificateVerify messages that use the handshake - * hash. */ - if (sigAndHash.hashAlg != hashes->hashAlg) { - errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM; - desc = decrypt_error; - goto alert_loser; - } - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - - /* XXX verify that the key & kea match */ - rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash, - isTLS, ss->pkcs11PinArg); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - desc = isTLS ? decrypt_error : handshake_failure; - goto alert_loser; - } - - signed_hash.data = NULL; - - if (length != 0) { - desc = isTLS ? decode_error : illegal_parameter; - goto alert_loser; /* malformed */ - } - ss->ssl3.hs.ws = wait_change_cipher; - return SECSuccess; - -alert_loser: - SSL3_SendAlert(ss, alert_fatal, desc); -loser: - PORT_SetError(errCode); - return SECFailure; -} - -/* find a slot that is able to generate a PMS and wrap it with RSA. - * Then generate and return the PMS. - * If the serverKeySlot parameter is non-null, this function will use - * that slot to do the job, otherwise it will find a slot. - * - * Called from ssl3_DeriveConnectionKeysPKCS11() (above) - * sendRSAClientKeyExchange() (above) - * ssl3_HandleRSAClientKeyExchange() (below) - * Caller must hold the SpecWriteLock, the SSL3HandshakeLock - */ -static PK11SymKey * -ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, - PK11SlotInfo *serverKeySlot) -{ - PK11SymKey *pms = NULL; - PK11SlotInfo *slot = serverKeySlot; - void *pwArg = ss->pkcs11PinArg; - SECItem param; - CK_VERSION version; - CK_MECHANISM_TYPE mechanism_array[3]; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (slot == NULL) { - SSLCipherAlgorithm calg; - /* The specReadLock would suffice here, but we cannot assert on - ** read locks. Also, all the callers who call with a non-null - ** slot already hold the SpecWriteLock. - */ - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - calg = spec->cipher_def->calg; - - /* First get an appropriate slot. */ - mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; - mechanism_array[1] = CKM_RSA_PKCS; - mechanism_array[2] = ssl3_Alg2Mech(calg); - - slot = PK11_GetBestSlotMultiple(mechanism_array, 3, pwArg); - if (slot == NULL) { - /* can't find a slot with all three, find a slot with the minimum */ - slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg); - if (slot == NULL) { - PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND); - return pms; /* which is NULL */ - } - } - } - - /* Generate the pre-master secret ... */ - if (IS_DTLS(ss)) { - SSL3ProtocolVersion temp; - - temp = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion); - version.major = MSB(temp); - version.minor = LSB(temp); - } else { - version.major = MSB(ss->clientHelloVersion); - version.minor = LSB(ss->clientHelloVersion); - } - - param.data = (unsigned char *)&version; - param.len = sizeof version; - - pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, ¶m, 0, pwArg); - if (!serverKeySlot) - PK11_FreeSlot(slot); - if (pms == NULL) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - } - return pms; -} - -/* Note: The Bleichenbacher attack on PKCS#1 necessitates that we NEVER - * return any indication of failure of the Client Key Exchange message, - * where that failure is caused by the content of the client's message. - * This function must not return SECFailure for any reason that is directly - * or indirectly caused by the content of the client's encrypted PMS. - * We must not send an alert and also not drop the connection. - * Instead, we generate a random PMS. This will cause a failure - * in the processing the finished message, which is exactly where - * the failure must occur. - * - * Called from ssl3_HandleClientKeyExchange - */ -static SECStatus -ssl3_HandleRSAClientKeyExchange(sslSocket *ss, - SSL3Opaque *b, - PRUint32 length, - SECKEYPrivateKey *serverKey) -{ -#ifndef NO_PKCS11_BYPASS - unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random; - unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random; - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - unsigned int outLen = 0; - PRBool isTLS = PR_FALSE; - SECItem pmsItem = { siBuffer, NULL, 0 }; - unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH]; -#endif - SECStatus rv; - SECItem enc_pms; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - enc_pms.data = b; - enc_pms.len = length; -#ifndef NO_PKCS11_BYPASS - pmsItem.data = rsaPmsBuf; - pmsItem.len = sizeof rsaPmsBuf; -#endif - - if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - PRInt32 kLen; - kLen = ssl3_ConsumeHandshakeNumber(ss, 2, &enc_pms.data, &enc_pms.len); - if (kLen < 0) { - PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - if ((unsigned)kLen < enc_pms.len) { - enc_pms.len = kLen; - } -#ifndef NO_PKCS11_BYPASS - isTLS = PR_TRUE; -#endif - } else { -#ifndef NO_PKCS11_BYPASS - isTLS = (PRBool)(ss->ssl3.hs.kea_def->tls_keygen != 0); -#endif - } - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - /* We have not implemented a tls_ExtendedMasterKeyDeriveBypass - * and will not negotiate this extension in bypass mode. This - * assert just double-checks that. - */ - PORT_Assert( - !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)); - - /* TRIPLE BYPASS, get PMS directly from RSA decryption. - * Use PK11_PrivDecryptPKCS1 to decrypt the PMS to a buffer, - * then, check for version rollback attack, then - * do the equivalent of ssl3_DeriveMasterSecret, placing the MS in - * pwSpec->msItem. Finally call ssl3_InitPendingCipherSpec with - * ss and NULL, so that it will use the MS we've already derived here. - */ - - rv = PK11_PrivDecryptPKCS1(serverKey, rsaPmsBuf, &outLen, - sizeof rsaPmsBuf, enc_pms.data, enc_pms.len); - if (rv != SECSuccess) { - /* triple bypass failed. Let's try for a double bypass. */ - goto double_bypass; - } else if (ss->opt.detectRollBack) { - SSL3ProtocolVersion client_version = - (rsaPmsBuf[0] << 8) | rsaPmsBuf[1]; - - if (IS_DTLS(ss)) { - client_version = dtls_DTLSVersionToTLSVersion(client_version); - } - - if (client_version != ss->clientHelloVersion) { - /* Version roll-back detected. ensure failure. */ - rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf); - } - } - /* have PMS, build MS without PKCS11 */ - rv = ssl3_MasterSecretDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS, - PR_TRUE); - if (rv != SECSuccess) { - pwSpec->msItem.data = pwSpec->raw_master_secret; - pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH; - PK11_GenerateRandom(pwSpec->msItem.data, pwSpec->msItem.len); - } - rv = ssl3_InitPendingCipherSpec(ss, NULL); - } else -#endif - { - PK11SymKey *tmpPms[2] = { NULL, NULL }; - PK11SlotInfo *slot; - int useFauxPms = 0; -#define currentPms tmpPms[!useFauxPms] -#define unusedPms tmpPms[useFauxPms] -#define realPms tmpPms[1] -#define fauxPms tmpPms[0] - -#ifndef NO_PKCS11_BYPASS - double_bypass: -#endif - - /* - * Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1 - * as we can within the constraints of the PKCS#11 interface. - * - * 1. Unconditionally generate a bogus PMS (what RFC 5246 - * calls R). - * 2. Attempt the RSA decryption to recover the PMS (what - * RFC 5246 calls M). - * 3. Set PMS = (M == NULL) ? R : M - * 4. Use ssl3_ComputeMasterSecret(PMS) to attempt to derive - * the MS from PMS. This includes performing the version - * check and length check. - * 5. If either the initial RSA decryption failed or - * ssl3_ComputeMasterSecret(PMS) failed, then discard - * M and set PMS = R. Else, discard R and set PMS = M. - * - * We do two derivations here because we can't rely on having - * a function that only performs the PMS version and length - * check. The only redundant cost is that this runs the PRF, - * which isn't necessary here. - */ - - /* Generate the bogus PMS (R) */ - slot = PK11_GetSlotFromPrivateKey(serverKey); - if (!slot) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - if (!PK11_DoesMechanism(slot, CKM_SSL3_MASTER_KEY_DERIVE)) { - PK11_FreeSlot(slot); - slot = PK11_GetBestSlot(CKM_SSL3_MASTER_KEY_DERIVE, NULL); - if (!slot) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - } - - ssl_GetSpecWriteLock(ss); - fauxPms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot); - ssl_ReleaseSpecWriteLock(ss); - PK11_FreeSlot(slot); - - if (fauxPms == NULL) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - - /* - * unwrap pms out of the incoming buffer - * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do - * the unwrap. Rather, it is the mechanism with which the - * unwrapped pms will be used. - */ - realPms = PK11_PubUnwrapSymKey(serverKey, &enc_pms, - CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0); - /* Temporarily use the PMS if unwrapping the real PMS fails. */ - useFauxPms |= (realPms == NULL); - - /* Attempt to derive the MS from the PMS. This is the only way to - * check the version field in the RSA PMS. If this fails, we - * then use the faux PMS in place of the PMS. Note that this - * operation should never fail if we are using the faux PMS - * since it is correctly formatted. */ - rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL); - - /* If we succeeded, then select the true PMS and discard the - * FPMS. Else, select the FPMS and select the true PMS */ - useFauxPms |= (rv != SECSuccess); - - if (unusedPms) { - PK11_FreeSymKey(unusedPms); - } - - /* This step will derive the MS from the PMS, among other things. */ - rv = ssl3_InitPendingCipherSpec(ss, currentPms); - PK11_FreeSymKey(currentPms); - } - - if (rv != SECSuccess) { - SEND_ALERT - return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ - } - -#undef currentPms -#undef unusedPms -#undef realPms -#undef fauxPms - - return SECSuccess; -} - -static SECStatus -ssl3_HandleDHClientKeyExchange(sslSocket *ss, - SSL3Opaque *b, - PRUint32 length, - SECKEYPublicKey *srvrPubKey, - SECKEYPrivateKey *serverKey) -{ - PK11SymKey *pms; - SECStatus rv; - SECKEYPublicKey clntPubKey; - CK_MECHANISM_TYPE target; - PRBool isTLS; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(srvrPubKey); - - clntPubKey.keyType = dhKey; - clntPubKey.u.dh.prime.len = srvrPubKey->u.dh.prime.len; - clntPubKey.u.dh.prime.data = srvrPubKey->u.dh.prime.data; - clntPubKey.u.dh.base.len = srvrPubKey->u.dh.base.len; - clntPubKey.u.dh.base.data = srvrPubKey->u.dh.base.data; - - rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.dh.publicValue, - 2, &b, &length); - if (rv != SECSuccess) { - goto loser; - } - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - - if (isTLS) - target = CKM_TLS_MASTER_KEY_DERIVE_DH; - else - target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - - /* Determine the PMS */ - pms = PK11_PubDerive(serverKey, &clntPubKey, PR_FALSE, NULL, NULL, - CKM_DH_PKCS_DERIVE, target, CKA_DERIVE, 0, NULL); - if (pms == NULL) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); - pms = NULL; - -loser: - if (ss->dheKeyPair) { - ssl3_FreeKeyPair(ss->dheKeyPair); - ss->dheKeyPair = NULL; - } - return rv; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 ClientKeyExchange message from the remote client - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECKEYPrivateKey *serverKey = NULL; - SECStatus rv; - const ssl3KEADef *kea_def; - ssl3KeyPair *serverKeyPair = NULL; - SECKEYPublicKey *serverPubKey = NULL; - - SSL_TRC(3, ("%d: SSL3[%d]: handle client_key_exchange handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.hs.ws != wait_client_key) { - SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH); - return SECFailure; - } - - kea_def = ss->ssl3.hs.kea_def; - - if (ss->ssl3.hs.usedStepDownKey) { - PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */ - && - kea_def->exchKeyType == kt_rsa && - ss->stepDownKeyPair != NULL); - if (!kea_def->is_limited || - kea_def->exchKeyType != kt_rsa || - ss->stepDownKeyPair == NULL) { - /* shouldn't happen, don't use step down if it does */ - goto skip; - } - serverKeyPair = ss->stepDownKeyPair; - ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; - } else - skip: - if (kea_def->kea == kea_dhe_dss || - kea_def->kea == kea_dhe_rsa) { - if (ss->dheKeyPair) { - serverKeyPair = ss->dheKeyPair; - if (serverKeyPair->pubKey) { - ss->sec.keaKeyBits = - SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); - } - } - } else -#ifndef NSS_DISABLE_ECC - /* XXX Using SSLKEAType to index server certifiates - * does not work for (EC)DHE ciphers. Until we have - * an indexing mechanism general enough for all key - * exchange algorithms, we'll need to deal with each - * one seprately. - */ - if ((kea_def->kea == kea_ecdhe_rsa) || - (kea_def->kea == kea_ecdhe_ecdsa)) { - if (ss->ephemeralECDHKeyPair != NULL) { - serverKeyPair = ss->ephemeralECDHKeyPair; - if (serverKeyPair->pubKey) { - ss->sec.keaKeyBits = - SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); - } - } - } else -#endif - { - sslServerCerts *sc = ss->serverCerts + kea_def->exchKeyType; - serverKeyPair = sc->serverKeyPair; - ss->sec.keaKeyBits = sc->serverKeyBits; - } - - if (serverKeyPair) { - serverKey = serverKeyPair->privKey; - } - - if (serverKey == NULL) { - SEND_ALERT - PORT_SetError(SSL_ERROR_NO_SERVER_KEY_FOR_ALG); - return SECFailure; - } - - ss->sec.keaType = kea_def->exchKeyType; - - switch (kea_def->exchKeyType) { - case kt_rsa: - rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKey); - if (rv != SECSuccess) { - SEND_ALERT - return SECFailure; /* error code set */ - } - break; - - case ssl_kea_dh: - if (ss->dheKeyPair && ss->dheKeyPair->pubKey) { - serverPubKey = ss->dheKeyPair->pubKey; - } - if (!serverPubKey) { - PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - return SECFailure; - } - rv = ssl3_HandleDHClientKeyExchange(ss, b, length, - serverPubKey, serverKey); - if (rv != SECSuccess) { - SSL3_SendAlert(ss, alert_fatal, handshake_failure); - return SECFailure; /* error code set */ - } - break; - -#ifndef NSS_DISABLE_ECC - case kt_ecdh: - /* XXX We really ought to be able to store multiple - * EC certs (a requirement if we wish to support both - * ECDH-RSA and ECDH-ECDSA key exchanges concurrently). - * When we make that change, we'll need an index other - * than kt_ecdh to pick the right EC certificate. - */ - if (serverKeyPair) { - serverPubKey = serverKeyPair->pubKey; - } - if (serverPubKey == NULL) { - /* XXX Is this the right error code? */ - PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - return SECFailure; - } - rv = ssl3_HandleECDHClientKeyExchange(ss, b, length, - serverPubKey, serverKey); - if (ss->ephemeralECDHKeyPair) { - ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); - ss->ephemeralECDHKeyPair = NULL; - } - if (rv != SECSuccess) { - return SECFailure; /* error code set */ - } - break; -#endif /* NSS_DISABLE_ECC */ - - default: - (void)ssl3_HandshakeFailure(ss); - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); - return SECFailure; - } - ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher; - return SECSuccess; -} - -/* This is TLS's equivalent of sending a no_certificate alert. */ -SECStatus -ssl3_SendEmptyCertificate(sslSocket *ss) -{ - SECStatus rv; - unsigned int len = 0; - PRBool isTLS13 = PR_FALSE; - - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - len = ss->ssl3.hs.certReqContextLen + 1; - isTLS13 = PR_TRUE; - } - - rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3); - if (rv != SECSuccess) { - return rv; - } - - if (isTLS13) { - rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.certReqContext, - ss->ssl3.hs.certReqContextLen, 1); - if (rv != SECSuccess) { - return rv; - } - } - - return ssl3_AppendHandshakeNumber(ss, 0, 3); -} - -SECStatus -ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv; - SECItem ticketData; - - SSL_TRC(3, ("%d: SSL3[%d]: handle session_ticket handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - PORT_Assert(!ss->ssl3.hs.newSessionTicket.ticket.data); - PORT_Assert(!ss->ssl3.hs.receivedNewSessionTicket); - - if (ss->ssl3.hs.ws != wait_new_session_ticket) { - SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET); - return SECFailure; - } - - /* RFC5077 Section 3.3: "The client MUST NOT treat the ticket as valid - * until it has verified the server's Finished message." See the comment in - * ssl3_FinishHandshake for more details. - */ - ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time(); - if (length < 4) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); - return SECFailure; - } - ss->ssl3.hs.newSessionTicket.ticket_lifetime_hint = - (PRUint32)ssl3_ConsumeHandshakeNumber(ss, 4, &b, &length); - - rv = ssl3_ConsumeHandshakeVariable(ss, &ticketData, 2, &b, &length); - if (rv != SECSuccess || length != 0) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); - return SECFailure; /* malformed */ - } - /* If the server sent a zero-length ticket, ignore it and keep the - * existing ticket. */ - if (ticketData.len != 0) { - rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.newSessionTicket.ticket, - &ticketData); - if (rv != SECSuccess) { - return rv; - } - ss->ssl3.hs.receivedNewSessionTicket = PR_TRUE; - } - - ss->ssl3.hs.ws = wait_change_cipher; - return SECSuccess; -} - -#ifdef NISCC_TEST -static PRInt32 connNum = 0; - -static SECStatus -get_fake_cert(SECItem *pCertItem, int *pIndex) -{ - PRFileDesc *cf; - char *testdir; - char *startat; - char *stopat; - const char *extension; - int fileNum; - PRInt32 numBytes = 0; - PRStatus prStatus; - PRFileInfo info; - char cfn[100]; - - pCertItem->data = 0; - if ((testdir = PR_GetEnvSecure("NISCC_TEST")) == NULL) { - return SECSuccess; - } - *pIndex = (NULL != strstr(testdir, "root")); - extension = (strstr(testdir, "simple") ? "" : ".der"); - fileNum = PR_ATOMIC_INCREMENT(&connNum) - 1; - if ((startat = PR_GetEnvSecure("START_AT")) != NULL) { - fileNum += atoi(startat); - } - if ((stopat = PR_GetEnvSecure("STOP_AT")) != NULL && - fileNum >= atoi(stopat)) { - *pIndex = -1; - return SECSuccess; - } - sprintf(cfn, "%s/%08d%s", testdir, fileNum, extension); - cf = PR_Open(cfn, PR_RDONLY, 0); - if (!cf) { - goto loser; - } - prStatus = PR_GetOpenFileInfo(cf, &info); - if (prStatus != PR_SUCCESS) { - PR_Close(cf); - goto loser; - } - pCertItem = SECITEM_AllocItem(NULL, pCertItem, info.size); - if (pCertItem) { - numBytes = PR_Read(cf, pCertItem->data, info.size); - } - PR_Close(cf); - if (numBytes != info.size) { - SECITEM_FreeItem(pCertItem, PR_FALSE); - PORT_SetError(SEC_ERROR_IO); - goto loser; - } - fprintf(stderr, "using %s\n", cfn); - return SECSuccess; - -loser: - fprintf(stderr, "failed to use %s\n", cfn); - *pIndex = -1; - return SECFailure; -} -#endif - -/* - * Used by both client and server. - * Called from HandleServerHelloDone and from SendServerHelloSequence. - */ -SECStatus -ssl3_SendCertificate(sslSocket *ss) -{ - SECStatus rv; - CERTCertificateList *certChain; - int certChainLen = 0; - int i; - SSL3KEAType certIndex; -#ifdef NISCC_TEST - SECItem fakeCert; - int ndex = -1; -#endif - PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; - unsigned int contextLen = 0; - - SSL_TRC(3, ("%d: SSL3[%d]: send certificate handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->sec.localCert) - CERT_DestroyCertificate(ss->sec.localCert); - if (ss->sec.isServer) { - sslServerCerts *sc = NULL; - - /* XXX SSLKEAType isn't really a good choice for - * indexing certificates (it breaks when we deal - * with (EC)DHE-* cipher suites. This hack ensures - * the RSA cert is picked for (EC)DHE-RSA. - * Revisit this when we add server side support - * for ECDHE-ECDSA or client-side authentication - * using EC certificates. - */ - if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) || - (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) { - certIndex = kt_rsa; - } else { - certIndex = ss->ssl3.hs.kea_def->exchKeyType; - } - sc = ss->serverCerts + certIndex; - certChain = sc->serverCertChain; - ss->sec.authKeyBits = sc->serverKeyBits; - ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType; - ss->sec.localCert = CERT_DupCertificate(sc->serverCert); - } else { - certChain = ss->ssl3.clientCertChain; - ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate); - } - -#ifdef NISCC_TEST - rv = get_fake_cert(&fakeCert, &ndex); -#endif - - if (isTLS13) { - contextLen = 1; /* Length of the context */ - if (!ss->sec.isServer) { - contextLen += ss->ssl3.hs.certReqContextLen; - } - } - if (certChain) { - for (i = 0; i < certChain->len; i++) { -#ifdef NISCC_TEST - if (fakeCert.len > 0 && i == ndex) { - certChainLen += fakeCert.len + 3; - } else { - certChainLen += certChain->certs[i].len + 3; - } -#else - certChainLen += certChain->certs[i].len + 3; -#endif - } - } - - rv = ssl3_AppendHandshakeHeader(ss, certificate, - contextLen + certChainLen + 3); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - - if (isTLS13) { - if (ss->sec.isServer) { - rv = ssl3_AppendHandshakeNumber(ss, 0, 1); - } else { - rv = ssl3_AppendHandshakeVariable(ss, - ss->ssl3.hs.certReqContext, - ss->ssl3.hs.certReqContextLen, 1); - } - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - - rv = ssl3_AppendHandshakeNumber(ss, certChainLen, 3); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - if (certChain) { - for (i = 0; i < certChain->len; i++) { -#ifdef NISCC_TEST - if (fakeCert.len > 0 && i == ndex) { - rv = ssl3_AppendHandshakeVariable(ss, fakeCert.data, - fakeCert.len, 3); - SECITEM_FreeItem(&fakeCert, PR_FALSE); - } else { - rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, - certChain->certs[i].len, 3); - } -#else - rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, - certChain->certs[i].len, 3); -#endif - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - } - - return SECSuccess; -} - -/* - * Used by server only. - * single-stapling, send only a single cert status - */ -SECStatus -ssl3_SendCertificateStatus(sslSocket *ss) -{ - SECStatus rv; - int len = 0; - SECItemArray *statusToSend = NULL; - SSL3KEAType certIndex; - - SSL_TRC(3, ("%d: SSL3[%d]: send certificate status handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->sec.isServer); - - if (!ssl3_ExtensionNegotiated(ss, ssl_cert_status_xtn)) - return SECSuccess; - - /* Use certStatus based on the cert being used. */ - if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) || - (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) { - certIndex = kt_rsa; - } else { - certIndex = ss->ssl3.hs.kea_def->exchKeyType; - } - if (ss->certStatusArray[certIndex] && ss->certStatusArray[certIndex]->len) { - statusToSend = ss->certStatusArray[certIndex]; - } - if (!statusToSend) - return SECSuccess; - - /* Use the array's first item only (single stapling) */ - len = 1 + statusToSend->items[0].len + 3; - - rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - rv = ssl3_AppendHandshakeNumber(ss, 1 /*ocsp*/, 1); - if (rv != SECSuccess) - return rv; /* err set by AppendHandshake. */ - - rv = ssl3_AppendHandshakeVariable(ss, - statusToSend->items[0].data, - statusToSend->items[0].len, - 3); - if (rv != SECSuccess) - return rv; /* err set by AppendHandshake. */ - - return SECSuccess; -} - -/* This is used to delete the CA certificates in the peer certificate chain - * from the cert database after they've been validated. - */ -static void -ssl3_CleanupPeerCerts(sslSocket *ss) -{ - PLArenaPool *arena = ss->ssl3.peerCertArena; - ssl3CertNode *certs = (ssl3CertNode *)ss->ssl3.peerCertChain; - - for (; certs; certs = certs->next) { - CERT_DestroyCertificate(certs->cert); - } - if (arena) - PORT_FreeArena(arena, PR_FALSE); - ss->ssl3.peerCertArena = NULL; - ss->ssl3.peerCertChain = NULL; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 CertificateStatus message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - if (ss->ssl3.hs.ws != wait_certificate_status) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS); - return SECFailure; - } - - return ssl3_CompleteHandleCertificateStatus(ss, b, length); -} - -/* Called from: - * ssl3_HandleCertificateStatus - * tls13_HandleCertificateStatus - */ -SECStatus -ssl3_CompleteHandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, - PRUint32 length) -{ - PRInt32 status, len; - - PORT_Assert(!ss->sec.isServer); - - /* Consume the CertificateStatusType enum */ - status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length); - if (status != 1 /* ocsp */) { - goto format_loser; - } - - len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (len != length) { - goto format_loser; - } - -#define MAX_CERTSTATUS_LEN 0x1ffff /* 128k - 1 */ - if (length > MAX_CERTSTATUS_LEN) - goto format_loser; -#undef MAX_CERTSTATUS_LEN - - /* Array size 1, because we currently implement single-stapling only */ - SECITEM_AllocArray(NULL, &ss->sec.ci.sid->peerCertStatus, 1); - if (!ss->sec.ci.sid->peerCertStatus.items) - return SECFailure; - - ss->sec.ci.sid->peerCertStatus.items[0].data = PORT_Alloc(length); - - if (!ss->sec.ci.sid->peerCertStatus.items[0].data) { - SECITEM_FreeArray(&ss->sec.ci.sid->peerCertStatus, PR_FALSE); - return SECFailure; - } - - PORT_Memcpy(ss->sec.ci.sid->peerCertStatus.items[0].data, b, length); - ss->sec.ci.sid->peerCertStatus.items[0].len = length; - ss->sec.ci.sid->peerCertStatus.items[0].type = siBuffer; - - return ssl3_AuthCertificate(ss); - -format_loser: - return ssl3_DecodeError(ss); -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 Certificate message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if ((ss->sec.isServer && ss->ssl3.hs.ws != wait_client_cert) || - (!ss->sec.isServer && ss->ssl3.hs.ws != wait_server_cert)) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE); - return SECFailure; - } - - return ssl3_CompleteHandleCertificate(ss, b, length); -} - -/* Called from ssl3_HandleCertificate - */ -SECStatus -ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - ssl3CertNode *c; - ssl3CertNode *lastCert = NULL; - PRInt32 remaining = 0; - PRInt32 size; - SECStatus rv; - PRBool isServer = (PRBool)(!!ss->sec.isServer); - PRBool isTLS; - SSL3AlertDescription desc; - int errCode = SSL_ERROR_RX_MALFORMED_CERTIFICATE; - SECItem certItem; - - if (ss->sec.peerCert != NULL) { - if (ss->sec.peerKey) { - SECKEY_DestroyPublicKey(ss->sec.peerKey); - ss->sec.peerKey = NULL; - } - CERT_DestroyCertificate(ss->sec.peerCert); - ss->sec.peerCert = NULL; - } - - ssl3_CleanupPeerCerts(ss); - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - - /* It is reported that some TLS client sends a Certificate message - ** with a zero-length message body. We'll treat that case like a - ** normal no_certificates message to maximize interoperability. - */ - if (length) { - remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (remaining < 0) - goto loser; /* fatal alert already sent by ConsumeHandshake. */ - if ((PRUint32)remaining > length) - goto decode_loser; - } - - if (!remaining) { - if (!(isTLS && isServer)) { - desc = bad_certificate; - goto alert_loser; - } - /* This is TLS's version of a no_certificate alert. */ - /* I'm a server. I've requested a client cert. He hasn't got one. */ - rv = ssl3_HandleNoCertificate(ss); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - goto loser; - } - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - ss->ssl3.hs.ws = wait_client_key; - } else { - TLS13_SET_HS_STATE(ss, wait_finished); - } - return SECSuccess; - } - - ss->ssl3.peerCertArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (ss->ssl3.peerCertArena == NULL) { - goto loser; /* don't send alerts on memory errors */ - } - - /* First get the peer cert. */ - remaining -= 3; - if (remaining < 0) - goto decode_loser; - - size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (size <= 0) - goto loser; /* fatal alert already sent by ConsumeHandshake. */ - - if (remaining < size) - goto decode_loser; - - certItem.data = b; - certItem.len = size; - b += size; - length -= size; - remaining -= size; - - ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL, - PR_FALSE, PR_TRUE); - if (ss->sec.peerCert == NULL) { - /* We should report an alert if the cert was bad, but not if the - * problem was just some local problem, like memory error. - */ - goto ambiguous_err; - } - - /* Now get all of the CA certs. */ - while (remaining > 0) { - remaining -= 3; - if (remaining < 0) - goto decode_loser; - - size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (size <= 0) - goto loser; /* fatal alert already sent by ConsumeHandshake. */ - - if (remaining < size) - goto decode_loser; - - certItem.data = b; - certItem.len = size; - b += size; - length -= size; - remaining -= size; - - c = PORT_ArenaNew(ss->ssl3.peerCertArena, ssl3CertNode); - if (c == NULL) { - goto loser; /* don't send alerts on memory errors */ - } - - c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL, - PR_FALSE, PR_TRUE); - if (c->cert == NULL) { - goto ambiguous_err; - } - - c->next = NULL; - if (lastCert) { - lastCert->next = c; - } else { - ss->ssl3.peerCertChain = c; - } - lastCert = c; - } - - if (remaining != 0) - goto decode_loser; - - SECKEY_UpdateCertPQG(ss->sec.peerCert); - - if (!isServer && ssl3_ExtensionNegotiated(ss, ssl_cert_status_xtn)) { - ss->ssl3.hs.ws = wait_certificate_status; - rv = SECSuccess; - } else { - rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */ - } - - return rv; - -ambiguous_err: - errCode = PORT_GetError(); - switch (errCode) { - case PR_OUT_OF_MEMORY_ERROR: - case SEC_ERROR_BAD_DATABASE: - case SEC_ERROR_NO_MEMORY: - if (isTLS) { - desc = internal_error; - goto alert_loser; - } - goto loser; - } - ssl3_SendAlertForCertError(ss, errCode); - goto loser; - -decode_loser: - desc = isTLS ? decode_error : bad_certificate; - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, desc); - -loser: - (void)ssl_MapLowLevelError(errCode); - return SECFailure; -} - -static SECStatus -ssl3_AuthCertificate(sslSocket *ss) -{ - SECStatus rv; - PRBool isServer = (PRBool)(!!ss->sec.isServer); - int errCode; - - ss->ssl3.hs.authCertificatePending = PR_FALSE; - - PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == - ssl_preinfo_all); - /* - * Ask caller-supplied callback function to validate cert chain. - */ - rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, ss->fd, - PR_TRUE, isServer); - if (rv != SECSuccess) { - errCode = PORT_GetError(); - if (rv != SECWouldBlock) { - if (ss->handleBadCert) { - rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd); - } - } - - if (rv == SECWouldBlock) { - if (ss->sec.isServer) { - errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS; - rv = SECFailure; - goto loser; - } - /* TODO(ekr@rtfm.com): Reenable for TLS 1.3 */ - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION; - rv = SECFailure; - goto loser; - } - - ss->ssl3.hs.authCertificatePending = PR_TRUE; - rv = SECSuccess; - } - - if (rv != SECSuccess) { - ssl3_SendAlertForCertError(ss, errCode); - goto loser; - } - } - - ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); - ssl3_CopyPeerCertsToSID(ss->ssl3.peerCertChain, ss->sec.ci.sid); - - if (!ss->sec.isServer) { - CERTCertificate *cert = ss->sec.peerCert; - - /* set the server authentication type and size from the value - ** in the cert. */ - SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert); - ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType; - ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; - if (pubKey) { - KeyType pubKeyType; - PRInt32 minKey; - /* This partly fixes Bug 124230 and may cause problems for - * callers which depend on the old (wrong) behavior. */ - ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); - pubKeyType = SECKEY_GetPublicKeyType(pubKey); - minKey = ss->sec.authKeyBits; - switch (pubKeyType) { - case rsaKey: - case rsaPssKey: - case rsaOaepKey: - rv = - NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minKey); - if (rv != - SECSuccess) { - minKey = - SSL_RSA_MIN_MODULUS_BITS; - } - break; - case dsaKey: - rv = - NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minKey); - if (rv != - SECSuccess) { - minKey = - SSL_DSA_MIN_P_BITS; - } - break; - case dhKey: - rv = - NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minKey); - if (rv != - SECSuccess) { - minKey = - SSL_DH_MIN_P_BITS; - } - break; - default: - break; - } - - /* Too small: not good enough. Send a fatal alert. */ - /* We aren't checking EC here on the understanding that we only - * support curves we like, a decision that might need revisiting. */ - if (ss->sec.authKeyBits < minKey) { - PORT_SetError(SSL_ERROR_WEAK_SERVER_CERT_KEY); - (void)SSL3_SendAlert(ss, alert_fatal, - ss->version >= SSL_LIBRARY_VERSION_TLS_1_0 - ? insufficient_security - : illegal_parameter); - SECKEY_DestroyPublicKey(pubKey); - return SECFailure; - } - SECKEY_DestroyPublicKey(pubKey); - pubKey = NULL; - } - - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - TLS13_SET_HS_STATE(ss, wait_cert_verify); - } else { - /* Ephemeral suites require ServerKeyExchange. Export cipher suites - * with RSA key exchange also require ServerKeyExchange if the - * authentication key exceeds the key size limit. */ - if (ss->ssl3.hs.kea_def->ephemeral || - (ss->ssl3.hs.kea_def->is_limited && - ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa && - ss->sec.authKeyBits > ss->ssl3.hs.kea_def->key_size_limit)) { - /* require server_key_exchange */ - ss->ssl3.hs.ws = wait_server_key; - } else { - /* disallow server_key_exchange */ - ss->ssl3.hs.ws = wait_cert_request; - /* This is static RSA key exchange so set the key bits to - * auth bits. */ - ss->sec.keaKeyBits = ss->sec.authKeyBits; - } - } - } else { - /* Server */ - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - ss->ssl3.hs.ws = wait_client_key; - } else { - TLS13_SET_HS_STATE(ss, wait_cert_verify); - } - } - - PORT_Assert(rv == SECSuccess); - if (rv != SECSuccess) { - errCode = SEC_ERROR_LIBRARY_FAILURE; - rv = SECFailure; - goto loser; - } - - return rv; - -loser: - (void)ssl_MapLowLevelError(errCode); - return SECFailure; -} - -static SECStatus ssl3_FinishHandshake(sslSocket *ss); - -static SECStatus -ssl3_AlwaysFail(sslSocket *ss) -{ - PORT_SetError(PR_INVALID_STATE_ERROR); - return SECFailure; -} - -/* Caller must hold 1stHandshakeLock. -*/ -SECStatus -ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error) -{ - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - if (ss->sec.isServer) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS); - return SECFailure; - } - - ssl_GetRecvBufLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (!ss->ssl3.hs.authCertificatePending) { - PORT_SetError(PR_INVALID_STATE_ERROR); - rv = SECFailure; - goto done; - } - - ss->ssl3.hs.authCertificatePending = PR_FALSE; - - if (error != 0) { - ss->ssl3.hs.restartTarget = ssl3_AlwaysFail; - ssl3_SendAlertForCertError(ss, error); - rv = SECSuccess; - } else if (ss->ssl3.hs.restartTarget != NULL) { - sslRestartTarget target = ss->ssl3.hs.restartTarget; - ss->ssl3.hs.restartTarget = NULL; - - if (target == ssl3_FinishHandshake) { - SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication lost the race" - " with peer's finished message", - SSL_GETPID(), ss->fd)); - } - - rv = target(ss); - /* Even if we blocked here, we have accomplished enough to claim - * success. Any remaining work will be taken care of by subsequent - * calls to SSL_ForceHandshake/PR_Send/PR_Read/etc. - */ - if (rv == SECWouldBlock) { - rv = SECSuccess; - } - } else { - SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race with" - " peer's finished message", - SSL_GETPID(), ss->fd)); - - PORT_Assert(!ss->ssl3.hs.isResuming); - PORT_Assert(ss->ssl3.hs.ws != idle_handshake); - - if (ss->opt.enableFalseStart && - !ss->firstHsDone && - !ss->ssl3.hs.isResuming && - ssl3_WaitingForServerSecondRound(ss)) { - /* ssl3_SendClientSecondRound deferred the false start check because - * certificate authentication was pending, so we do it now if we still - * haven't received all of the server's second round yet. - */ - rv = ssl3_CheckFalseStart(ss); - } else { - rv = SECSuccess; - } - } - -done: - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_ReleaseRecvBufLock(ss); - - return rv; -} - -static SECStatus -ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, - PRBool isServer, - const SSL3Hashes *hashes, - TLSFinished *tlsFinished) -{ - SECStatus rv; - CK_TLS_MAC_PARAMS tls_mac_params; - SECItem param = { siBuffer, NULL, 0 }; - PK11Context *prf_context; - unsigned int retLen; - - if (!spec->master_secret || spec->bypassCiphers) { - const char *label = isServer ? "server finished" : "client finished"; - unsigned int len = 15; - - return ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw, - hashes->len, tlsFinished->verify_data, - sizeof tlsFinished->verify_data); - } - - if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) { - tls_mac_params.prfMechanism = CKM_TLS_PRF; - } else { - tls_mac_params.prfMechanism = CKM_SHA256; - } - tls_mac_params.ulMacLength = 12; - tls_mac_params.ulServerOrClient = isServer ? 1 : 2; - param.data = (unsigned char *)&tls_mac_params; - param.len = sizeof(tls_mac_params); - prf_context = PK11_CreateContextBySymKey(CKM_TLS_MAC, CKA_SIGN, - spec->master_secret, ¶m); - if (!prf_context) - return SECFailure; - - rv = PK11_DigestBegin(prf_context); - rv |= PK11_DigestOp(prf_context, hashes->u.raw, hashes->len); - rv |= PK11_DigestFinal(prf_context, tlsFinished->verify_data, &retLen, - sizeof tlsFinished->verify_data); - PORT_Assert(rv != SECSuccess || retLen == sizeof tlsFinished->verify_data); - - PK11_DestroyContext(prf_context, PR_TRUE); - - return rv; -} - -/* The calling function must acquire and release the appropriate - * lock (e.g., ssl_GetSpecReadLock / ssl_ReleaseSpecReadLock for - * ss->ssl3.crSpec). - */ -SECStatus -ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label, - unsigned int labelLen, const unsigned char *val, unsigned int valLen, - unsigned char *out, unsigned int outLen) -{ - SECStatus rv = SECSuccess; - - if (spec->master_secret && !spec->bypassCiphers) { - SECItem param = { siBuffer, NULL, 0 }; - CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; - PK11Context *prf_context; - unsigned int retLen; - - if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; - } - prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, - spec->master_secret, ¶m); - if (!prf_context) - return SECFailure; - - rv = PK11_DigestBegin(prf_context); - rv |= PK11_DigestOp(prf_context, (unsigned char *)label, labelLen); - rv |= PK11_DigestOp(prf_context, val, valLen); - rv |= PK11_DigestFinal(prf_context, out, &retLen, outLen); - PORT_Assert(rv != SECSuccess || retLen == outLen); - - PK11_DestroyContext(prf_context, PR_TRUE); - } else { -/* bypass PKCS11 */ -#ifdef NO_PKCS11_BYPASS - PORT_Assert(spec->master_secret); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; -#else - SECItem inData = { siBuffer }; - SECItem outData = { siBuffer }; - PRBool isFIPS = PR_FALSE; - - inData.data = (unsigned char *)val; - inData.len = valLen; - outData.data = out; - outData.len = outLen; - if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - rv = TLS_P_hash(HASH_AlgSHA256, &spec->msItem, label, &inData, - &outData, isFIPS); - } else { - rv = TLS_PRF(&spec->msItem, label, &inData, &outData, isFIPS); - } - PORT_Assert(rv != SECSuccess || outData.len == outLen); -#endif - } - return rv; -} - -/* called from ssl3_SendClientSecondRound - * ssl3_HandleFinished - */ -static SECStatus -ssl3_SendNextProto(sslSocket *ss) -{ - SECStatus rv; - int padding_len; - static const unsigned char padding[32] = { 0 }; - - if (ss->ssl3.nextProto.len == 0 || - ss->ssl3.nextProtoState == SSL_NEXT_PROTO_SELECTED) { - return SECSuccess; - } - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - padding_len = 32 - ((ss->ssl3.nextProto.len + 2) % 32); - - rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->ssl3.nextProto.len + - 2 + - padding_len); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshakeHeader */ - } - rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data, - ss->ssl3.nextProto.len, 1); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake */ - } - rv = ssl3_AppendHandshakeVariable(ss, padding, padding_len, 1); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake */ - } - return rv; -} - -/* called from ssl3_SendFinished - * - * This function is simply a debugging aid and therefore does not return a - * SECStatus. */ -static void -ssl3_RecordKeyLog(sslSocket *ss) -{ - SECStatus rv; - SECItem *keyData; - char buf[14 /* "CLIENT_RANDOM " */ + - SSL3_RANDOM_LENGTH * 2 /* client_random */ + - 1 /* " " */ + - 48 * 2 /* master secret */ + - 1 /* new line */]; - unsigned int j; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (!ssl_keylog_iob) - return; - - rv = PK11_ExtractKeyValue(ss->ssl3.cwSpec->master_secret); - if (rv != SECSuccess) - return; - - ssl_GetSpecReadLock(ss); - - /* keyData does not need to be freed. */ - keyData = PK11_GetKeyData(ss->ssl3.cwSpec->master_secret); - if (!keyData || !keyData->data || keyData->len != 48) { - ssl_ReleaseSpecReadLock(ss); - return; - } - - /* https://developer.mozilla.org/en/NSS_Key_Log_Format */ - - /* There could be multiple, concurrent writers to the - * keylog, so we have to do everything in a single call to - * fwrite. */ - - memcpy(buf, "CLIENT_RANDOM ", 14); - j = 14; - hexEncode(buf + j, ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); - j += SSL3_RANDOM_LENGTH * 2; - buf[j++] = ' '; - hexEncode(buf + j, keyData->data, 48); - j += 48 * 2; - buf[j++] = '\n'; - - PORT_Assert(j == sizeof(buf)); - - ssl_ReleaseSpecReadLock(ss); - - if (fwrite(buf, sizeof(buf), 1, ssl_keylog_iob) != 1) - return; - fflush(ssl_keylog_iob); - return; -} - -/* called from ssl3_SendClientSecondRound - * ssl3_HandleFinished - */ -static SECStatus -ssl3_SendChannelIDEncryptedExtensions(sslSocket *ss) -{ - static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; - static const char CHANNEL_ID_RESUMPTION_MAGIC[] = "Resumption"; - /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: - * SEQUENCE - * SEQUENCE - * OID id-ecPublicKey - * OID prime256v1 - * BIT STRING, length 66, 0 trailing bits: 0x04 - * - * The 0x04 in the BIT STRING is the prefix for an uncompressed, X9.62 - * public key. Following that are the two field elements as 32-byte, - * big-endian numbers, as required by the Channel ID. */ - static const unsigned char P256_SPKI_PREFIX[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, - 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, - 0x42, 0x00, 0x04 - }; - /* ChannelIDs are always 128 bytes long: 64 bytes of P-256 public key and 64 - * bytes of ECDSA signature. */ - static const int CHANNEL_ID_PUBLIC_KEY_LENGTH = 64; - static const int CHANNEL_ID_LENGTH = 128; - - SECStatus rv = SECFailure; - SECItem *spki = NULL; - SSL3Hashes hashes; - const unsigned char *pub_bytes; - unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + - sizeof(CHANNEL_ID_RESUMPTION_MAGIC) + - sizeof(SSL3Hashes) * 2]; - size_t signed_data_len; - unsigned char digest[SHA256_LENGTH]; - SECItem digest_item; - unsigned char signature[64]; - SECItem signature_item; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.channelID == NULL) - return SECSuccess; - - PORT_Assert(ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)); - - if (SECKEY_GetPrivateKeyType(ss->ssl3.channelID) != ecKey || - PK11_SignatureLen(ss->ssl3.channelID) != sizeof(signature)) { - PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); - rv = SECFailure; - goto loser; - } - - ssl_GetSpecReadLock(ss); - rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); - ssl_ReleaseSpecReadLock(ss); - - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshakeHeader(ss, channelid_encrypted_extensions, - 2 + 2 + CHANNEL_ID_LENGTH); - if (rv != SECSuccess) - goto loser; /* error code set by AppendHandshakeHeader */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); - if (rv != SECSuccess) - goto loser; /* error code set by AppendHandshake */ - rv = ssl3_AppendHandshakeNumber(ss, CHANNEL_ID_LENGTH, 2); - if (rv != SECSuccess) - goto loser; /* error code set by AppendHandshake */ - - spki = SECKEY_EncodeDERSubjectPublicKeyInfo(ss->ssl3.channelIDPub); - - if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH || - memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX)) != 0) { - PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); - rv = SECFailure; - goto loser; - } - - pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); - - signed_data_len = 0; - memcpy(signed_data + signed_data_len, CHANNEL_ID_MAGIC, - sizeof(CHANNEL_ID_MAGIC)); - signed_data_len += sizeof(CHANNEL_ID_MAGIC); - if (ss->ssl3.hs.isResuming) { - SECItem *originalHandshakeHash = - &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; - PORT_Assert(originalHandshakeHash->len > 0); - - memcpy(signed_data + signed_data_len, CHANNEL_ID_RESUMPTION_MAGIC, - sizeof(CHANNEL_ID_RESUMPTION_MAGIC)); - signed_data_len += sizeof(CHANNEL_ID_RESUMPTION_MAGIC); - memcpy(signed_data + signed_data_len, originalHandshakeHash->data, - originalHandshakeHash->len); - signed_data_len += originalHandshakeHash->len; - } - memcpy(signed_data + signed_data_len, hashes.u.raw, hashes.len); - signed_data_len += hashes.len; - - rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, signed_data_len); - if (rv != SECSuccess) - goto loser; - - digest_item.data = digest; - digest_item.len = sizeof(digest); - - signature_item.data = signature; - signature_item.len = sizeof(signature); - - rv = PK11_Sign(ss->ssl3.channelID, &signature_item, &digest_item); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshake(ss, pub_bytes, CHANNEL_ID_PUBLIC_KEY_LENGTH); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshake(ss, signature, sizeof(signature)); - -loser: - if (spki) - SECITEM_FreeItem(spki, PR_TRUE); - if (ss->ssl3.channelID) { - SECKEY_DestroyPrivateKey(ss->ssl3.channelID); - ss->ssl3.channelID = NULL; - } - if (ss->ssl3.channelIDPub) { - SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); - ss->ssl3.channelIDPub = NULL; - } - - return rv; -} - -/* ssl3_RestartHandshakeAfterChannelIDReq is called to restart a handshake - * after a ChannelID callback returned SECWouldBlock. At this point we have - * processed the server's ServerHello but not yet any further messages. We will - * always get a message from the server after a ServerHello so either they are - * waiting in the buffer or we'll get network I/O. */ -SECStatus -ssl3_RestartHandshakeAfterChannelIDReq(sslSocket *ss, - SECKEYPublicKey *channelIDPub, - SECKEYPrivateKey *channelID) -{ - if (ss->handshake == 0) { - SECKEY_DestroyPublicKey(channelIDPub); - SECKEY_DestroyPrivateKey(channelID); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - if (channelIDPub == NULL || - channelID == NULL) { - if (channelIDPub) - SECKEY_DestroyPublicKey(channelIDPub); - if (channelID) - SECKEY_DestroyPrivateKey(channelID); - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - - if (ss->ssl3.channelID) - SECKEY_DestroyPrivateKey(ss->ssl3.channelID); - if (ss->ssl3.channelIDPub) - SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); - - ss->handshake = ssl_GatherRecord1stHandshake; - ss->ssl3.channelID = channelID; - ss->ssl3.channelIDPub = channelIDPub; - - return SECSuccess; -} - -/* called from ssl3_SendClientSecondRound - * ssl3_HandleClientHello - * ssl3_HandleFinished - */ -static SECStatus -ssl3_SendFinished(sslSocket *ss, PRInt32 flags) -{ - ssl3CipherSpec *cwSpec; - PRBool isTLS; - PRBool isServer = ss->sec.isServer; - SECStatus rv; - SSL3Sender sender = isServer ? sender_server : sender_client; - SSL3Hashes hashes; - TLSFinished tlsFinished; - - SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - ssl_GetSpecReadLock(ss); - cwSpec = ss->ssl3.cwSpec; - isTLS = (PRBool)(cwSpec->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_ComputeHandshakeHashes(ss, cwSpec, &hashes, sender); - if (isTLS && rv == SECSuccess) { - rv = ssl3_ComputeTLSFinished(cwSpec, isServer, &hashes, &tlsFinished); - } - ssl_ReleaseSpecReadLock(ss); - if (rv != SECSuccess) { - goto fail; /* err code was set by ssl3_ComputeHandshakeHashes */ - } - - if (isTLS) { - if (isServer) - ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished; - else - ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished; - ss->ssl3.hs.finishedBytes = sizeof tlsFinished; - rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished); - if (rv != SECSuccess) - goto fail; /* err set by AppendHandshake. */ - rv = ssl3_AppendHandshake(ss, &tlsFinished, sizeof tlsFinished); - if (rv != SECSuccess) - goto fail; /* err set by AppendHandshake. */ - } else { - if (isServer) - ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s; - else - ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s; - PORT_Assert(hashes.len == sizeof hashes.u.s); - ss->ssl3.hs.finishedBytes = sizeof hashes.u.s; - rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s); - if (rv != SECSuccess) - goto fail; /* err set by AppendHandshake. */ - rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s); - if (rv != SECSuccess) - goto fail; /* err set by AppendHandshake. */ - } - rv = ssl3_FlushHandshake(ss, flags); - if (rv != SECSuccess) { - goto fail; /* error code set by ssl3_FlushHandshake */ - } - - ssl3_RecordKeyLog(ss); - - return SECSuccess; - -fail: - return rv; -} - -/* wrap the master secret, and put it into the SID. - * Caller holds the Spec read lock. - */ -SECStatus -ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, - ssl3CipherSpec *spec, SSL3KEAType effectiveExchKeyType) -{ - PK11SymKey *wrappingKey = NULL; - PK11SlotInfo *symKeySlot; - void *pwArg = ss->pkcs11PinArg; - SECStatus rv = SECFailure; - PRBool isServer = ss->sec.isServer; - CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; - symKeySlot = PK11_GetSlotFromKey(spec->master_secret); - if (!isServer) { - int wrapKeyIndex; - int incarnation; - - /* these next few functions are mere accessors and don't fail. */ - sid->u.ssl3.masterWrapIndex = wrapKeyIndex = - PK11_GetCurrentWrapIndex(symKeySlot); - PORT_Assert(wrapKeyIndex == 0); /* array has only one entry! */ - - sid->u.ssl3.masterWrapSeries = incarnation = - PK11_GetSlotSeries(symKeySlot); - sid->u.ssl3.masterSlotID = PK11_GetSlotID(symKeySlot); - sid->u.ssl3.masterModuleID = PK11_GetModuleID(symKeySlot); - sid->u.ssl3.masterValid = PR_TRUE; - /* Get the default wrapping key, for wrapping the master secret before - * placing it in the SID cache entry. */ - wrappingKey = PK11_GetWrapKey(symKeySlot, wrapKeyIndex, - CKM_INVALID_MECHANISM, incarnation, - pwArg); - if (wrappingKey) { - mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ - } else { - int keyLength; - /* if the wrappingKey doesn't exist, attempt to create it. - * Note: we intentionally ignore errors here. If we cannot - * generate a wrapping key, it is not fatal to this SSL connection, - * but we will not be able to restart this session. - */ - mechanism = PK11_GetBestWrapMechanism(symKeySlot); - keyLength = PK11_GetBestKeyLength(symKeySlot, mechanism); - /* Zero length means fixed key length algorithm, or error. - * It's ambiguous. - */ - wrappingKey = PK11_KeyGen(symKeySlot, mechanism, NULL, - keyLength, pwArg); - if (wrappingKey) { - PK11_SetWrapKey(symKeySlot, wrapKeyIndex, wrappingKey); - } - } - } else { - /* server socket using session cache. */ - mechanism = PK11_GetBestWrapMechanism(symKeySlot); - if (mechanism != CKM_INVALID_MECHANISM) { - wrappingKey = - getWrappingKey(ss, symKeySlot, effectiveExchKeyType, - mechanism, pwArg); - if (wrappingKey) { - mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ - } - } - } - - sid->u.ssl3.masterWrapMech = mechanism; - PK11_FreeSlot(symKeySlot); - - if (wrappingKey) { - SECItem wmsItem; - - wmsItem.data = sid->u.ssl3.keys.wrapped_master_secret; - wmsItem.len = sizeof sid->u.ssl3.keys.wrapped_master_secret; - rv = PK11_WrapSymKey(mechanism, NULL, wrappingKey, - spec->master_secret, &wmsItem); - /* rv is examined below. */ - sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len; - PK11_FreeSymKey(wrappingKey); - } - return rv; -} - -/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered - * a complete ssl3 Finished message from the peer. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, - const SSL3Hashes *hashes) -{ - sslSessionID *sid = ss->sec.ci.sid; - SECStatus rv = SECSuccess; - PRBool isServer = ss->sec.isServer; - PRBool isTLS; - SSL3KEAType effectiveExchKeyType; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - SSL_TRC(3, ("%d: SSL3[%d]: handle finished handshake", - SSL_GETPID(), ss->fd)); - - if (ss->ssl3.hs.ws != wait_finished) { - SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_FINISHED); - return SECFailure; - } - - if (!hashes) { - PORT_Assert(0); - SSL3_SendAlert(ss, alert_fatal, internal_error); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0); - if (isTLS) { - TLSFinished tlsFinished; - - if (length != sizeof tlsFinished) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED); - return SECFailure; - } - rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer, - hashes, &tlsFinished); - if (!isServer) - ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished; - else - ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished; - ss->ssl3.hs.finishedBytes = sizeof tlsFinished; - if (rv != SECSuccess || - 0 != NSS_SecureMemcmp(&tlsFinished, b, length)) { - (void)SSL3_SendAlert(ss, alert_fatal, decrypt_error); - PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); - return SECFailure; - } - } else { - if (length != sizeof(SSL3Finished)) { - (void)ssl3_IllegalParameter(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED); - return SECFailure; - } - - if (!isServer) - ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s; - else - ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s; - PORT_Assert(hashes->len == sizeof hashes->u.s); - ss->ssl3.hs.finishedBytes = sizeof hashes->u.s; - if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) { - (void)ssl3_HandshakeFailure(ss); - PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); - return SECFailure; - } - } - - ssl_GetXmitBufLock(ss); /*************************************/ - - if ((isServer && !ss->ssl3.hs.isResuming) || - (!isServer && ss->ssl3.hs.isResuming)) { - PRInt32 flags = 0; - - /* Send a NewSessionTicket message if the client sent us - * either an empty session ticket, or one that did not verify. - * (Note that if either of these conditions was met, then the - * server has sent a SessionTicket extension in the - * ServerHello message.) - */ - if (isServer && !ss->ssl3.hs.isResuming && - ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && - ssl3_KEAAllowsSessionTicket(ss->ssl3.hs.suite_def->key_exchange_alg)) { - /* RFC 5077 Section 3.3: "In the case of a full handshake, the - * server MUST verify the client's Finished message before sending - * the ticket." Presumably, this also means that the client's - * certificate, if any, must be verified beforehand too. - */ - rv = ssl3_SendNewSessionTicket(ss); - if (rv != SECSuccess) { - goto xmit_loser; - } - } - - rv = ssl3_SendChangeCipherSpecs(ss); - if (rv != SECSuccess) { - goto xmit_loser; /* err is set. */ - } - /* If this thread is in SSL_SecureSend (trying to write some data) - ** then set the ssl_SEND_FLAG_FORCE_INTO_BUFFER flag, so that the - ** last two handshake messages (change cipher spec and finished) - ** will be sent in the same send/write call as the application data. - */ - if (ss->writerThread == PR_GetCurrentThread()) { - flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; - } - - if (!isServer) { - if (!ss->firstHsDone) { - rv = ssl3_SendNextProto(ss); - if (rv != SECSuccess) { - goto xmit_loser; /* err code was set. */ - } - } - rv = ssl3_SendChannelIDEncryptedExtensions(ss); - if (rv != SECSuccess) - goto xmit_loser; /* err code was set. */ - } - - if (IS_DTLS(ss)) { - flags |= ssl_SEND_FLAG_NO_RETRANSMIT; - } - - rv = ssl3_SendFinished(ss, flags); - if (rv != SECSuccess) { - goto xmit_loser; /* err is set. */ - } - } - -xmit_loser: - ssl_ReleaseXmitBufLock(ss); /*************************************/ - if (rv != SECSuccess) { - return rv; - } - - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa || - ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) { - effectiveExchKeyType = kt_rsa; - } else { - effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; - } - - if (sid->cached == never_cached && !ss->opt.noCache && ss->sec.cache) { - /* fill in the sid */ - sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite; - sid->u.ssl3.compression = ss->ssl3.hs.compression; - sid->u.ssl3.policy = ss->ssl3.policy; -#ifndef NSS_DISABLE_ECC - sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves; -#endif - sid->u.ssl3.exchKeyType = effectiveExchKeyType; - sid->version = ss->version; - sid->authAlgorithm = ss->sec.authAlgorithm; - sid->authKeyBits = ss->sec.authKeyBits; - sid->keaType = ss->sec.keaType; - sid->keaKeyBits = ss->sec.keaKeyBits; - sid->lastAccessTime = sid->creationTime = ssl_Time(); - sid->expirationTime = sid->creationTime + ssl3_sid_timeout; - sid->localCert = CERT_DupCertificate(ss->sec.localCert); - - ssl_GetSpecReadLock(ss); /*************************************/ - - /* Copy the master secret (wrapped or unwrapped) into the sid */ - if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) { - sid->u.ssl3.keys.wrapped_master_secret_len = - ss->ssl3.crSpec->msItem.len; - memcpy(sid->u.ssl3.keys.wrapped_master_secret, - ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len); - sid->u.ssl3.masterValid = PR_TRUE; - sid->u.ssl3.keys.msIsWrapped = PR_FALSE; - rv = SECSuccess; - } else { - rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid, - ss->ssl3.crSpec, - effectiveExchKeyType); - sid->u.ssl3.keys.msIsWrapped = PR_TRUE; - } - ssl_ReleaseSpecReadLock(ss); /*************************************/ - - /* If the wrap failed, we don't cache the sid. - * The connection continues normally however. - */ - ss->ssl3.hs.cacheSID = rv == SECSuccess; - } - - if (ss->ssl3.hs.authCertificatePending) { - if (ss->ssl3.hs.restartTarget) { - PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget"); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - ss->ssl3.hs.restartTarget = ssl3_FinishHandshake; - return SECWouldBlock; - } - - rv = ssl3_FinishHandshake(ss); - return rv; -} - -/* The return type is SECStatus instead of void because this function needs - * to have type sslRestartTarget. - */ -SECStatus -ssl3_FinishHandshake(sslSocket *ss) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.hs.restartTarget == NULL); - - /* The first handshake is now completed. */ - ss->handshake = NULL; - - /* RFC 5077 Section 3.3: "The client MUST NOT treat the ticket as valid - * until it has verified the server's Finished message." When the server - * sends a NewSessionTicket in a resumption handshake, we must wait until - * the handshake is finished (we have verified the server's Finished - * AND the server's certificate) before we update the ticket in the sid. - * - * This must be done before we call (*ss->sec.cache)(ss->sec.ci.sid) - * because CacheSID requires the session ticket to already be set, and also - * because of the lazy lock creation scheme used by CacheSID and - * ssl3_SetSIDSessionTicket. - */ - if (ss->ssl3.hs.receivedNewSessionTicket) { - PORT_Assert(!ss->sec.isServer); - ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ss->ssl3.hs.newSessionTicket); - /* The sid took over the ticket data */ - PORT_Assert(!ss->ssl3.hs.newSessionTicket.ticket.data); - ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE; - } - - if (ss->ssl3.hs.cacheSID && ss->sec.isServer) { - PORT_Assert(ss->sec.ci.sid->cached == never_cached); - (*ss->sec.cache)(ss->sec.ci.sid); - ss->ssl3.hs.cacheSID = PR_FALSE; - } - - ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */ - ss->ssl3.hs.ws = idle_handshake; - - ssl_FinishHandshake(ss); - - return SECSuccess; -} - -/* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3 - * hanshake message. - * Caller must hold Handshake and RecvBuf locks. - */ -SECStatus -ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv = SECSuccess; - SSL3HandshakeType type = ss->ssl3.hs.msg_type; - SSL3Hashes hashes; /* computed hashes are put here. */ - SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */ - PRUint8 hdr[4]; - PRUint8 dtlsData[8]; - PRBool computeHashes = PR_FALSE; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - /* - * We have to compute the hashes before we update them with the - * current message. - */ - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - if (((type == finished) && (ss->ssl3.hs.ws == wait_finished)) || - ((type == certificate_verify) && - (ss->ssl3.hs.ws == wait_cert_verify))) { - computeHashes = PR_TRUE; - } - } else { - if (type == certificate_verify) { - computeHashes = - TLS13_IN_HS_STATE(ss, wait_cert_verify); - } else if (type == finished) { - computeHashes = - TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished); - } - } - - ssl_GetSpecReadLock(ss); /************************************/ - if (computeHashes) { - SSL3Sender sender = (SSL3Sender)0; - ssl3CipherSpec *rSpec = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.crSpec - : ss->ssl3.prSpec; - - if (type == finished) { - sender = ss->sec.isServer ? sender_client : sender_server; - rSpec = ss->ssl3.crSpec; - } - rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender); - if (rv == SECSuccess) { - hashesPtr = &hashes; - } - } - ssl_ReleaseSpecReadLock(ss); /************************************/ - if (rv != SECSuccess) { - return rv; /* error code was set by ssl3_ComputeHandshakeHashes*/ - } - SSL_TRC(30, ("%d: SSL3[%d]: handle handshake message: %s", SSL_GETPID(), - ss->fd, ssl3_DecodeHandshakeType(ss->ssl3.hs.msg_type))); - - hdr[0] = (PRUint8)ss->ssl3.hs.msg_type; - hdr[1] = (PRUint8)(length >> 16); - hdr[2] = (PRUint8)(length >> 8); - hdr[3] = (PRUint8)(length); - - /* Start new handshake hashes when we start a new handshake */ - if (ss->ssl3.hs.msg_type == client_hello) { - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - return rv; - } - } - /* We should not include hello_request and hello_verify_request messages - * in the handshake hashes */ - if ((ss->ssl3.hs.msg_type != hello_request) && - (ss->ssl3.hs.msg_type != hello_verify_request)) { - rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4); - if (rv != SECSuccess) - return rv; /* err code already set. */ - - /* Extra data to simulate a complete DTLS handshake fragment */ - if (IS_DTLS(ss)) { - /* Sequence number */ - dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq); - dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq); - - /* Fragment offset */ - dtlsData[2] = 0; - dtlsData[3] = 0; - dtlsData[4] = 0; - - /* Fragment length */ - dtlsData[5] = (PRUint8)(length >> 16); - dtlsData[6] = (PRUint8)(length >> 8); - dtlsData[7] = (PRUint8)(length); - - rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData, - sizeof(dtlsData)); - if (rv != SECSuccess) - return rv; /* err code already set. */ - } - - /* The message body */ - rv = ssl3_UpdateHandshakeHashes(ss, b, length); - if (rv != SECSuccess) - return rv; /* err code already set. */ - } - - PORT_SetError(0); /* each message starts with no error. */ - - if (ss->ssl3.hs.ws == wait_certificate_status && - ss->ssl3.hs.msg_type != certificate_status) { - /* If we negotiated the certificate_status extension then we deferred - * certificate validation until we get the CertificateStatus messsage. - * But the CertificateStatus message is optional. If the server did - * not send it then we need to validate the certificate now. If the - * server does send the CertificateStatus message then we will - * authenticate the certificate in ssl3_HandleCertificateStatus. - */ - rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */ - PORT_Assert(rv != SECWouldBlock); - if (rv != SECSuccess) { - return rv; - } - } - - switch (ss->ssl3.hs.msg_type) { - case client_hello: - if (!ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO); - return SECFailure; - } - rv = ssl3_HandleClientHello(ss, b, length); - break; - case server_hello: - if (ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO); - return SECFailure; - } - rv = ssl3_HandleServerHello(ss, b, length); - break; - default: - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length, hashesPtr); - } else { - rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length, - hashesPtr); - } - break; - } - - if (IS_DTLS(ss) && (rv != SECFailure)) { - /* Increment the expected sequence number */ - ss->ssl3.hs.recvMessageSeq++; - } - return rv; -} - -static SECStatus -ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b, - PRUint32 length, SSL3Hashes *hashesPtr) -{ - SECStatus rv; - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - - switch (ss->ssl3.hs.msg_type) { - case hello_request: - if (length != 0) { - (void)ssl3_DecodeError(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST); - return SECFailure; - } - if (ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST); - return SECFailure; - } - rv = ssl3_HandleHelloRequest(ss); - break; - case hello_verify_request: - if (!IS_DTLS(ss) || ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST); - return SECFailure; - } - rv = dtls_HandleHelloVerifyRequest(ss, b, length); - break; - case certificate: - rv = ssl3_HandleCertificate(ss, b, length); - break; - case certificate_status: - rv = ssl3_HandleCertificateStatus(ss, b, length); - break; - case server_key_exchange: - if (ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH); - return SECFailure; - } - rv = ssl3_HandleServerKeyExchange(ss, b, length); - break; - case certificate_request: - if (ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST); - return SECFailure; - } - rv = ssl3_HandleCertificateRequest(ss, b, length); - break; - case server_hello_done: - if (length != 0) { - (void)ssl3_DecodeError(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_DONE); - return SECFailure; - } - if (ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE); - return SECFailure; - } - rv = ssl3_HandleServerHelloDone(ss); - break; - case certificate_verify: - if (!ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY); - return SECFailure; - } - rv = ssl3_HandleCertificateVerify(ss, b, length, hashesPtr); - break; - case client_key_exchange: - if (!ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH); - return SECFailure; - } - rv = ssl3_HandleClientKeyExchange(ss, b, length); - break; - case new_session_ticket: - if (ss->sec.isServer) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET); - return SECFailure; - } - rv = ssl3_HandleNewSessionTicket(ss, b, length); - break; - case finished: - rv = ssl3_HandleFinished(ss, b, length, hashesPtr); - break; - default: - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE); - rv = SECFailure; - } - - return rv; -} - -/* Called only from ssl3_HandleRecord, for each (deciphered) ssl3 record. - * origBuf is the decrypted ssl record content. - * Caller must hold the handshake and RecvBuf locks. - */ -static SECStatus -ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) -{ - /* - * There may be a partial handshake message already in the handshake - * state. The incoming buffer may contain another portion, or a - * complete message or several messages followed by another portion. - * - * Each message is made contiguous before being passed to the actual - * message parser. - */ - sslBuffer *buf = &ss->ssl3.hs.msgState; /* do not lose the original buffer pointer */ - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (buf->buf == NULL) { - *buf = *origBuf; - } - while (buf->len > 0) { - if (ss->ssl3.hs.header_bytes < 4) { - PRUint8 t; - t = *(buf->buf++); - buf->len--; - if (ss->ssl3.hs.header_bytes++ == 0) - ss->ssl3.hs.msg_type = (SSL3HandshakeType)t; - else - ss->ssl3.hs.msg_len = (ss->ssl3.hs.msg_len << 8) + t; - if (ss->ssl3.hs.header_bytes < 4) - continue; - -#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */ - if (ss->ssl3.hs.msg_len > MAX_HANDSHAKE_MSG_LEN) { - (void)ssl3_DecodeError(ss); - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); - return SECFailure; - } -#undef MAX_HANDSHAKE_MSG_LEN - - /* If msg_len is zero, be sure we fall through, - ** even if buf->len is zero. - */ - if (ss->ssl3.hs.msg_len > 0) - continue; - } - - /* - * Header has been gathered and there is at least one byte of new - * data available for this message. If it can be done right out - * of the original buffer, then use it from there. - */ - if (ss->ssl3.hs.msg_body.len == 0 && buf->len >= ss->ssl3.hs.msg_len) { - /* handle it from input buffer */ - rv = ssl3_HandleHandshakeMessage(ss, buf->buf, ss->ssl3.hs.msg_len); - if (rv == SECFailure) { - /* This test wants to fall through on either - * SECSuccess or SECWouldBlock. - * ssl3_HandleHandshakeMessage MUST set the error code. - */ - return rv; - } - buf->buf += ss->ssl3.hs.msg_len; - buf->len -= ss->ssl3.hs.msg_len; - ss->ssl3.hs.msg_len = 0; - ss->ssl3.hs.header_bytes = 0; - if (rv != SECSuccess) { /* return if SECWouldBlock. */ - return rv; - } - } else { - /* must be copied to msg_body and dealt with from there */ - unsigned int bytes; - - PORT_Assert(ss->ssl3.hs.msg_body.len < ss->ssl3.hs.msg_len); - bytes = PR_MIN(buf->len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len); - - /* Grow the buffer if needed */ - rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, ss->ssl3.hs.msg_len); - if (rv != SECSuccess) { - /* sslBuffer_Grow has set a memory error code. */ - return SECFailure; - } - - PORT_Memcpy(ss->ssl3.hs.msg_body.buf + ss->ssl3.hs.msg_body.len, - buf->buf, bytes); - ss->ssl3.hs.msg_body.len += bytes; - buf->buf += bytes; - buf->len -= bytes; - - PORT_Assert(ss->ssl3.hs.msg_body.len <= ss->ssl3.hs.msg_len); - - /* if we have a whole message, do it */ - if (ss->ssl3.hs.msg_body.len == ss->ssl3.hs.msg_len) { - rv = ssl3_HandleHandshakeMessage( - ss, ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len); - if (rv == SECFailure) { - /* This test wants to fall through on either - * SECSuccess or SECWouldBlock. - * ssl3_HandleHandshakeMessage MUST set error code. - */ - return rv; - } - ss->ssl3.hs.msg_body.len = 0; - ss->ssl3.hs.msg_len = 0; - ss->ssl3.hs.header_bytes = 0; - if (rv != SECSuccess) { /* return if SECWouldBlock. */ - return rv; - } - } else { - PORT_Assert(buf->len == 0); - break; - } - } - } /* end loop */ - - origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */ - buf->buf = NULL; /* not a leak. */ - return SECSuccess; -} - -/* These macros return the given value with the MSB copied to all the other - * bits. They use the fact that arithmetic shift shifts-in the sign bit. - * However, this is not ensured by the C standard so you may need to replace - * them with something else for odd compilers. */ -#define DUPLICATE_MSB_TO_ALL(x) ((unsigned)((int)(x) >> (sizeof(int) * 8 - 1))) -#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x))) - -/* SECStatusToMask returns, in constant time, a mask value of all ones if - * rv == SECSuccess. Otherwise it returns zero. */ -static unsigned int -SECStatusToMask(SECStatus rv) -{ - unsigned int good; - /* rv ^ SECSuccess is zero iff rv == SECSuccess. Subtracting one results - * in the MSB being set to one iff it was zero before. */ - good = rv ^ SECSuccess; - good--; - return DUPLICATE_MSB_TO_ALL(good); -} - -/* ssl_ConstantTimeGE returns 0xff if a>=b and 0x00 otherwise. */ -static unsigned char -ssl_ConstantTimeGE(unsigned int a, unsigned int b) -{ - a -= b; - return DUPLICATE_MSB_TO_ALL(~a); -} - -/* ssl_ConstantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */ -static unsigned char -ssl_ConstantTimeEQ8(unsigned char a, unsigned char b) -{ - unsigned int c = a ^ b; - c--; - return DUPLICATE_MSB_TO_ALL_8(c); -} - -static SECStatus -ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext, - unsigned int blockSize, - unsigned int macSize) -{ - unsigned int paddingLength, good, t; - const unsigned int overhead = 1 /* padding length byte */ + macSize; - - /* These lengths are all public so we can test them in non-constant - * time. */ - if (overhead > plaintext->len) { - return SECFailure; - } - - paddingLength = plaintext->buf[plaintext->len - 1]; - /* SSLv3 padding bytes are random and cannot be checked. */ - t = plaintext->len; - t -= paddingLength + overhead; - /* If len >= paddingLength+overhead then the MSB of t is zero. */ - good = DUPLICATE_MSB_TO_ALL(~t); - /* SSLv3 requires that the padding is minimal. */ - t = blockSize - (paddingLength + 1); - good &= DUPLICATE_MSB_TO_ALL(~t); - plaintext->len -= good & (paddingLength + 1); - return (good & SECSuccess) | (~good & SECFailure); -} - -static SECStatus -ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize) -{ - unsigned int paddingLength, good, t, toCheck, i; - const unsigned int overhead = 1 /* padding length byte */ + macSize; - - /* These lengths are all public so we can test them in non-constant - * time. */ - if (overhead > plaintext->len) { - return SECFailure; - } - - paddingLength = plaintext->buf[plaintext->len - 1]; - t = plaintext->len; - t -= paddingLength + overhead; - /* If len >= paddingLength+overhead then the MSB of t is zero. */ - good = DUPLICATE_MSB_TO_ALL(~t); - - /* The padding consists of a length byte at the end of the record and then - * that many bytes of padding, all with the same value as the length byte. - * Thus, with the length byte included, there are paddingLength+1 bytes of - * padding. - * - * We can't check just |paddingLength+1| bytes because that leaks - * decrypted information. Therefore we always have to check the maximum - * amount of padding possible. (Again, the length of the record is - * public information so we can use it.) */ - toCheck = 255; /* maximum amount of padding. */ - if (toCheck > plaintext->len - 1) { - toCheck = plaintext->len - 1; - } - - for (i = 0; i < toCheck; i++) { - unsigned int t = paddingLength - i; - /* If i <= paddingLength then the MSB of t is zero and mask is - * 0xff. Otherwise, mask is 0. */ - unsigned char mask = DUPLICATE_MSB_TO_ALL(~t); - unsigned char b = plaintext->buf[plaintext->len - 1 - i]; - /* The final |paddingLength+1| bytes should all have the value - * |paddingLength|. Therefore the XOR should be zero. */ - good &= ~(mask & (paddingLength ^ b)); - } - - /* If any of the final |paddingLength+1| bytes had the wrong value, - * one or more of the lower eight bits of |good| will be cleared. We - * AND the bottom 8 bits together and duplicate the result to all the - * bits. */ - good &= good >> 4; - good &= good >> 2; - good &= good >> 1; - good <<= sizeof(good) * 8 - 1; - good = DUPLICATE_MSB_TO_ALL(good); - - plaintext->len -= good & (paddingLength + 1); - return (good & SECSuccess) | (~good & SECFailure); -} - -/* On entry: - * originalLength >= macSize - * macSize <= MAX_MAC_LENGTH - * plaintext->len >= macSize - */ -static void -ssl_CBCExtractMAC(sslBuffer *plaintext, - unsigned int originalLength, - SSL3Opaque *out, - unsigned int macSize) -{ - unsigned char rotatedMac[MAX_MAC_LENGTH]; - /* macEnd is the index of |plaintext->buf| just after the end of the - * MAC. */ - unsigned macEnd = plaintext->len; - unsigned macStart = macEnd - macSize; - /* scanStart contains the number of bytes that we can ignore because - * the MAC's position can only vary by 255 bytes. */ - unsigned scanStart = 0; - unsigned i, j, divSpoiler; - unsigned char rotateOffset; - - if (originalLength > macSize + 255 + 1) - scanStart = originalLength - (macSize + 255 + 1); - - /* divSpoiler contains a multiple of macSize that is used to cause the - * modulo operation to be constant time. Without this, the time varies - * based on the amount of padding when running on Intel chips at least. - * - * The aim of right-shifting macSize is so that the compiler doesn't - * figure out that it can remove divSpoiler as that would require it - * to prove that macSize is always even, which I hope is beyond it. */ - divSpoiler = macSize >> 1; - divSpoiler <<= (sizeof(divSpoiler) - 1) * 8; - rotateOffset = (divSpoiler + macStart - scanStart) % macSize; - - memset(rotatedMac, 0, macSize); - for (i = scanStart; i < originalLength;) { - for (j = 0; j < macSize && i < originalLength; i++, j++) { - unsigned char macStarted = ssl_ConstantTimeGE(i, macStart); - unsigned char macEnded = ssl_ConstantTimeGE(i, macEnd); - unsigned char b = 0; - b = plaintext->buf[i]; - rotatedMac[j] |= b & macStarted & ~macEnded; - } - } - - /* Now rotate the MAC. If we knew that the MAC fit into a CPU cache line - * we could line-align |rotatedMac| and rotate in place. */ - memset(out, 0, macSize); - for (i = 0; i < macSize; i++) { - unsigned char offset = - (divSpoiler + macSize - rotateOffset + i) % macSize; - for (j = 0; j < macSize; j++) { - out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ8(j, offset); - } - } -} - -/* Unprotect an SSL3 record and leave the result in plaintext. - * - * If SECFailure is returned, we: - * 1. Set |*alert| to the alert to be sent. - * 2. Call PORT_SetError() with an appropriate code. - * - * Called by ssl3_HandleRecord. Caller must hold the spec read lock. - * Therefore, we MUST not call SSL3_SendAlert(). - * - */ -static SECStatus -ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, - SSL3AlertDescription *alert) -{ - ssl3CipherSpec *crSpec = ss->ssl3.crSpec; - const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def; - PRBool isTLS; - unsigned int good; - unsigned int ivLen = 0; - SSL3ContentType rType; - unsigned int minLength; - unsigned int originalLen = 0; - unsigned char header[13]; - unsigned int headerLen; - SSL3Opaque hash[MAX_MAC_LENGTH]; - SSL3Opaque givenHashBuf[MAX_MAC_LENGTH]; - SSL3Opaque *givenHash; - unsigned int hashBytes = MAX_MAC_LENGTH + 1; - SECStatus rv; - - good = ~0U; - minLength = crSpec->mac_size; - if (cipher_def->type == type_block) { - /* CBC records have a padding length byte at the end. */ - minLength++; - if (crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { - /* With >= TLS 1.1, CBC records have an explicit IV. */ - minLength += cipher_def->iv_size; - } - } else if (cipher_def->type == type_aead) { - minLength = cipher_def->explicit_nonce_size + cipher_def->tag_size; - } - - /* We can perform this test in variable time because the record's total - * length and the ciphersuite are both public knowledge. */ - if (cText->buf->len < minLength) { - goto decrypt_loser; - } - - if (cipher_def->type == type_block && - crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { - /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states - * "The receiver decrypts the entire GenericBlockCipher structure and - * then discards the first cipher block corresponding to the IV - * component." Instead, we decrypt the first cipher block and then - * discard it before decrypting the rest. - */ - SSL3Opaque iv[MAX_IV_LENGTH]; - int decoded; - - ivLen = cipher_def->iv_size; - if (ivLen < 8 || ivLen > sizeof(iv)) { - *alert = internal_error; - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - PRINT_BUF(80, (ss, "IV (ciphertext):", cText->buf->buf, ivLen)); - - /* The decryption result is garbage, but since we just throw away - * the block it doesn't matter. The decryption of the next block - * depends only on the ciphertext of the IV block. - */ - rv = crSpec->decode(crSpec->decodeContext, iv, &decoded, - sizeof(iv), cText->buf->buf, ivLen); - - good &= SECStatusToMask(rv); - } - - PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf + ivLen, - cText->buf->len - ivLen)); - - isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); - - if (isTLS && cText->buf->len - ivLen > (MAX_FRAGMENT_LENGTH + 2048)) { - *alert = record_overflow; - PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); - return SECFailure; - } - - rType = cText->type; - if (cipher_def->type == type_aead) { - /* XXX For many AEAD ciphers, the plaintext is shorter than the - * ciphertext by a fixed byte count, but it is not true in general. - * Each AEAD cipher should provide a function that returns the - * plaintext length for a given ciphertext. */ - unsigned int decryptedLen = - cText->buf->len - cipher_def->explicit_nonce_size - - cipher_def->tag_size; - headerLen = ssl3_BuildRecordPseudoHeader( - header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, - rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen); - PORT_Assert(headerLen <= sizeof(header)); - rv = crSpec->aead( - ss->sec.isServer ? &crSpec->client : &crSpec->server, - PR_TRUE, /* do decrypt */ - plaintext->buf, /* out */ - (int *)&plaintext->len, /* outlen */ - plaintext->space, /* maxout */ - cText->buf->buf, /* in */ - cText->buf->len, /* inlen */ - header, headerLen); - if (rv != SECSuccess) { - good = 0; - } - } else { - if (cipher_def->type == type_block && - ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) { - goto decrypt_loser; - } - - /* decrypt from cText buf to plaintext. */ - rv = crSpec->decode( - crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len, - plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen); - if (rv != SECSuccess) { - goto decrypt_loser; - } - - PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len)); - - originalLen = plaintext->len; - - /* If it's a block cipher, check and strip the padding. */ - if (cipher_def->type == type_block) { - const unsigned int blockSize = cipher_def->block_size; - const unsigned int macSize = crSpec->mac_size; - - if (!isTLS) { - good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding( - plaintext, blockSize, macSize)); - } else { - good &= SECStatusToMask(ssl_RemoveTLSCBCPadding( - plaintext, macSize)); - } - } - - /* compute the MAC */ - headerLen = ssl3_BuildRecordPseudoHeader( - header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, - rType, isTLS, cText->version, IS_DTLS(ss), - plaintext->len - crSpec->mac_size); - PORT_Assert(headerLen <= sizeof(header)); - if (cipher_def->type == type_block) { - rv = ssl3_ComputeRecordMACConstantTime( - crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, - plaintext->buf, plaintext->len, originalLen, - hash, &hashBytes); - - ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf, - crSpec->mac_size); - givenHash = givenHashBuf; - - /* plaintext->len will always have enough space to remove the MAC - * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust - * plaintext->len if the result has enough space for the MAC and we - * tested the unadjusted size against minLength, above. */ - plaintext->len -= crSpec->mac_size; - } else { - /* This is safe because we checked the minLength above. */ - plaintext->len -= crSpec->mac_size; - - rv = ssl3_ComputeRecordMAC( - crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, - plaintext->buf, plaintext->len, hash, &hashBytes); - - /* We can read the MAC directly from the record because its location - * is public when a stream cipher is used. */ - givenHash = plaintext->buf + plaintext->len; - } - - good &= SECStatusToMask(rv); - - if (hashBytes != (unsigned)crSpec->mac_size || - NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { - /* We're allowed to leak whether or not the MAC check was correct */ - good = 0; - } - } - - if (good == 0) { - decrypt_loser: - /* always log mac error, in case attacker can read server logs. */ - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - *alert = bad_record_mac; - return SECFailure; - } - return SECSuccess; -} - -/* if cText is non-null, then decipher, check MAC, and decompress the - * SSL record from cText->buf (typically gs->inbuf) - * into databuf (typically gs->buf), and any previous contents of databuf - * is lost. Then handle databuf according to its SSL record type, - * unless it's an application record. - * - * If cText is NULL, then the ciphertext has previously been deciphered and - * checked, and is already sitting in databuf. It is processed as an SSL - * Handshake message. - * - * DOES NOT process the decrypted/decompressed application data. - * On return, databuf contains the decrypted/decompressed record. - * - * Called from ssl3_GatherCompleteHandshake - * ssl3_RestartHandshakeAfterCertReq - * - * Caller must hold the RecvBufLock. - * - * This function aquires and releases the SSL3Handshake Lock, holding the - * lock around any calls to functions that handle records other than - * Application Data records. - */ -SECStatus -ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) -{ - SECStatus rv; - PRBool isTLS; - PRUint64 dtls_seq_num = 0; - ssl3CipherSpec *crSpec; - SSL3ContentType rType; - sslBuffer *plaintext; - sslBuffer temp_buf; - SSL3AlertDescription alert; - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - if (!ss->ssl3.initialized) { - ssl_GetSSL3HandshakeLock(ss); - rv = ssl3_InitState(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - if (rv != SECSuccess) { - return rv; /* ssl3_InitState has set the error code. */ - } - } - - /* check for Token Presence */ - if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) { - PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); - return SECFailure; - } - - /* cText is NULL when we're called from ssl3_RestartHandshakeAfterXXX(). - * This implies that databuf holds a previously deciphered SSL Handshake - * message. - */ - if (cText == NULL) { - SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake", - SSL_GETPID(), ss->fd)); - rType = content_handshake; - goto process_it; - } - - ssl_GetSpecReadLock(ss); /******************************************/ - crSpec = ss->ssl3.crSpec; - isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); - - if (IS_DTLS(ss)) { - if (!dtls_IsRelevant(ss, crSpec, cText, &dtls_seq_num)) { - ssl_ReleaseSpecReadLock(ss); - /* Silently drop the packet */ - databuf->len = 0; /* Needed to ensure data not left around */ - return SECSuccess; - } - } - - /* If we will be decompressing the buffer we need to decrypt somewhere - * other than into databuf */ - if (crSpec->decompressor) { - temp_buf.buf = NULL; - temp_buf.space = 0; - plaintext = &temp_buf; - } else { - plaintext = databuf; - } - - plaintext->len = 0; /* filled in by Unprotect call below. */ - if (plaintext->space < MAX_FRAGMENT_LENGTH) { - rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048); - if (rv != SECSuccess) { - ssl_ReleaseSpecReadLock(ss); - SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048)); - /* sslBuffer_Grow has set a memory error code. */ - /* Perhaps we should send an alert. (but we have no memory!) */ - return SECFailure; - } - } - - /* IMPORTANT: Unprotect functions MUST NOT send alerts - * because we still hold the spec read lock. Instead, if they - * return SECFailure, they set *alert to the alert to be sent. */ - if (crSpec->version < SSL_LIBRARY_VERSION_TLS_1_3 || - crSpec->cipher_def->calg == ssl_calg_null) { - /* Unencrypted TLS 1.3 records use the pre-TLS 1.3 format. */ - rv = ssl3_UnprotectRecord(ss, cText, plaintext, &alert); - } else { - rv = tls13_UnprotectRecord(ss, cText, plaintext, &alert); - } - - if (rv != SECSuccess) { - ssl_ReleaseSpecReadLock(ss); - - SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd)); - - if (!IS_DTLS(ss)) { - int errCode = PORT_GetError(); - SSL3_SendAlert(ss, alert_fatal, alert); - /* Reset the error code in case SSL3_SendAlert called - * PORT_SetError(). */ - PORT_SetError(errCode); - return SECFailure; - } else { - /* Silently drop the packet */ - databuf->len = 0; /* Needed to ensure data not left around */ - return SECSuccess; - } - } - - /* SECSuccess */ - if (!IS_DTLS(ss)) { - ssl3_BumpSequenceNumber(&crSpec->read_seq_num); - } else { - dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num); - } - - ssl_ReleaseSpecReadLock(ss); /*****************************************/ - - /* - * The decrypted data is now in plaintext. - */ - rType = cText->type; /* This must go after decryption because TLS 1.3 - * has encrypted content types. */ - - /* possibly decompress the record. If we aren't using compression then - * plaintext == databuf and so the uncompressed data is already in - * databuf. */ - if (crSpec->decompressor) { - if (databuf->space < plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION) { - rv = sslBuffer_Grow( - databuf, plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, - plaintext->len + - SSL3_COMPRESSION_MAX_EXPANSION)); - /* sslBuffer_Grow has set a memory error code. */ - /* Perhaps we should send an alert. (but we have no memory!) */ - PORT_Free(plaintext->buf); - return SECFailure; - } - } - - rv = crSpec->decompressor(crSpec->decompressContext, - databuf->buf, - (int *)&databuf->len, - databuf->space, - plaintext->buf, - plaintext->len); - - if (rv != SECSuccess) { - int err = ssl_MapLowLevelError(SSL_ERROR_DECOMPRESSION_FAILURE); - SSL3_SendAlert(ss, alert_fatal, - isTLS ? decompression_failure - : bad_record_mac); - - /* There appears to be a bug with (at least) Apache + OpenSSL where - * resumed SSLv3 connections don't actually use compression. See - * comments 93-95 of - * https://bugzilla.mozilla.org/show_bug.cgi?id=275744 - * - * So, if we get a decompression error, and the record appears to - * be already uncompressed, then we return a more specific error - * code to hopefully save somebody some debugging time in the - * future. - */ - if (plaintext->len >= 4) { - unsigned int len = ((unsigned int)plaintext->buf[1] << 16) | - ((unsigned int)plaintext->buf[2] << 8) | - (unsigned int)plaintext->buf[3]; - if (len == plaintext->len - 4) { - /* This appears to be uncompressed already */ - err = SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD; - } - } - - PORT_Free(plaintext->buf); - PORT_SetError(err); - return SECFailure; - } - - PORT_Free(plaintext->buf); - } - - /* - ** Having completed the decompression, check the length again. - */ - if (isTLS && databuf->len > (MAX_FRAGMENT_LENGTH + 1024)) { - SSL3_SendAlert(ss, alert_fatal, record_overflow); - PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); - return SECFailure; - } - - /* Application data records are processed by the caller of this - ** function, not by this function. - */ - if (rType == content_application_data) { - if (ss->firstHsDone) - return SECSuccess; - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA); - return SECFailure; - } - - /* It's a record that must be handled by ssl itself, not the application. - */ -process_it: - /* XXX Get the xmit lock here. Odds are very high that we'll be xmiting - * data ang getting the xmit lock here prevents deadlocks. - */ - ssl_GetSSL3HandshakeLock(ss); - - /* All the functions called in this switch MUST set error code if - ** they return SECFailure or SECWouldBlock. - */ - switch (rType) { - case content_change_cipher_spec: - rv = ssl3_HandleChangeCipherSpecs(ss, databuf); - break; - case content_alert: - rv = ssl3_HandleAlert(ss, databuf); - break; - case content_handshake: - if (!IS_DTLS(ss)) { - rv = ssl3_HandleHandshake(ss, databuf); - } else { - rv = dtls_HandleHandshake(ss, databuf); - } - break; - /* - case content_application_data is handled before this switch - */ - default: - SSL_DBG(("%d: SSL3[%d]: bogus content type=%d", - SSL_GETPID(), ss->fd, cText->type)); - /* XXX Send an alert ??? */ - PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE); - rv = SECFailure; - break; - } - - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; -} - -/* - * Initialization functions - */ - -/* Called from ssl3_InitState, immediately below. */ -/* Caller must hold the SpecWriteLock. */ -static void -ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) -{ - spec->cipher_def = &bulk_cipher_defs[cipher_null]; - PORT_Assert(spec->cipher_def->cipher == cipher_null); - spec->mac_def = &mac_defs[mac_null]; - PORT_Assert(spec->mac_def->mac == mac_null); - spec->encode = Null_Cipher; - spec->decode = Null_Cipher; - spec->destroy = NULL; - spec->compressor = NULL; - spec->decompressor = NULL; - spec->destroyCompressContext = NULL; - spec->destroyDecompressContext = NULL; - spec->mac_size = 0; - spec->master_secret = NULL; - spec->bypassCiphers = PR_FALSE; - - spec->msItem.data = NULL; - spec->msItem.len = 0; - - spec->client.write_key = NULL; - spec->client.write_mac_key = NULL; - spec->client.write_mac_context = NULL; - - spec->server.write_key = NULL; - spec->server.write_mac_key = NULL; - spec->server.write_mac_context = NULL; - - spec->write_seq_num.high = 0; - spec->write_seq_num.low = 0; - - spec->read_seq_num.high = 0; - spec->read_seq_num.low = 0; - - spec->epoch = 0; - dtls_InitRecvdRecords(&spec->recvdRecords); - - spec->version = ss->vrange.max; -} - -/* Called from: ssl3_SendRecord -** ssl3_StartHandshakeHash() <- ssl2_BeginClientHandshake() -** ssl3_SendClientHello() -** ssl3_HandleV2ClientHello() -** ssl3_HandleRecord() -** -** This function should perhaps acquire and release the SpecWriteLock. -** -** -*/ -static SECStatus -ssl3_InitState(sslSocket *ss) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.initialized) - return SECSuccess; /* Function should be idempotent */ - - ss->ssl3.policy = SSL_ALLOWED; - - ssl_GetSpecWriteLock(ss); - ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0]; - ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1]; - ss->ssl3.hs.sendingSCSV = PR_FALSE; - ssl3_InitCipherSpec(ss, ss->ssl3.crSpec); - ssl3_InitCipherSpec(ss, ss->ssl3.prSpec); - ss->ssl3.hs.preliminaryInfo = 0; - - ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; -#ifndef NSS_DISABLE_ECC - ss->ssl3.hs.negotiatedECCurves = ssl3_GetSupportedECCurveMask(ss); -#endif - ssl_ReleaseSpecWriteLock(ss); - - PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData)); - - if (IS_DTLS(ss)) { - ss->ssl3.hs.sendMessageSeq = 0; - ss->ssl3.hs.recvMessageSeq = 0; - ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; - ss->ssl3.hs.rtRetries = 0; - ss->ssl3.hs.recvdHighWater = -1; - PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight); - dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */ - } - - PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares); - ss->ssl3.hs.xSS = NULL; - ss->ssl3.hs.xES = NULL; - ss->ssl3.hs.trafficSecret = NULL; - ss->ssl3.hs.clientFinishedSecret = NULL; - ss->ssl3.hs.serverFinishedSecret = NULL; - ss->ssl3.hs.certReqContextLen = 0; - - PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); - ss->ssl3.hs.messages.buf = NULL; - ss->ssl3.hs.messages.space = 0; - - ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE; - PORT_Memset(&ss->ssl3.hs.newSessionTicket, 0, - sizeof(ss->ssl3.hs.newSessionTicket)); - - ss->ssl3.initialized = PR_TRUE; - return SECSuccess; -} - -/* Returns a reference counted object that contains a key pair. - * Or NULL on failure. Initial ref count is 1. - * Uses the keys in the pair as input. - */ -ssl3KeyPair * -ssl3_NewKeyPair(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey) -{ - ssl3KeyPair *pair; - - if (!privKey || !pubKey) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return NULL; - } - pair = PORT_ZNew(ssl3KeyPair); - if (!pair) - return NULL; /* error code is set. */ - pair->refCount = 1; - pair->privKey = privKey; - pair->pubKey = pubKey; - return pair; /* success */ -} - -ssl3KeyPair * -ssl3_GetKeyPairRef(ssl3KeyPair *keyPair) -{ - PR_ATOMIC_INCREMENT(&keyPair->refCount); - return keyPair; -} - -void -ssl3_FreeKeyPair(ssl3KeyPair *keyPair) -{ - PRInt32 newCount = PR_ATOMIC_DECREMENT(&keyPair->refCount); - if (!newCount) { - if (keyPair->privKey) - SECKEY_DestroyPrivateKey(keyPair->privKey); - if (keyPair->pubKey) - SECKEY_DestroyPublicKey(keyPair->pubKey); - PORT_Free(keyPair); - } -} - -/* - * Creates the public and private RSA keys for SSL Step down. - * Called from SSL_ConfigSecureServer in sslsecur.c - */ -SECStatus -ssl3_CreateRSAStepDownKeys(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - SECKEYPrivateKey *privKey; /* RSA step down key */ - SECKEYPublicKey *pubKey; /* RSA step down key */ - - if (ss->stepDownKeyPair) - ssl3_FreeKeyPair(ss->stepDownKeyPair); - ss->stepDownKeyPair = NULL; -#ifndef HACKED_EXPORT_SERVER - /* Sigh, should have a get key strength call for private keys */ - if (PK11_GetPrivateModulusLen(ss->serverCerts[kt_rsa].SERVERKEY) > - EXPORT_RSA_KEY_LENGTH) { - /* need to ask for the key size in bits */ - privKey = SECKEY_CreateRSAPrivateKey(EXPORT_RSA_KEY_LENGTH * BPB, - &pubKey, NULL); - if (!privKey || !pubKey || - !(ss->stepDownKeyPair = ssl3_NewKeyPair(privKey, pubKey))) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - } - } -#endif - return rv; -} - -/* record the export policy for this cipher suite */ -SECStatus -ssl3_SetPolicy(ssl3CipherSuite which, int policy) -{ - ssl3CipherSuiteCfg *suite; - - suite = ssl_LookupCipherSuiteCfg(which, cipherSuites); - if (suite == NULL) { - return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */ - } - suite->policy = policy; - - return SECSuccess; -} - -SECStatus -ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *oPolicy) -{ - ssl3CipherSuiteCfg *suite; - PRInt32 policy; - SECStatus rv; - - suite = ssl_LookupCipherSuiteCfg(which, cipherSuites); - if (suite) { - policy = suite->policy; - rv = SECSuccess; - } else { - policy = SSL_NOT_ALLOWED; - rv = SECFailure; /* err code was set by Lookup. */ - } - *oPolicy = policy; - return rv; -} - -/* record the user preference for this suite */ -SECStatus -ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool enabled) -{ - ssl3CipherSuiteCfg *suite; - - suite = ssl_LookupCipherSuiteCfg(which, cipherSuites); - if (suite == NULL) { - return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */ - } - suite->enabled = enabled; - return SECSuccess; -} - -/* return the user preference for this suite */ -SECStatus -ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *enabled) -{ - ssl3CipherSuiteCfg *suite; - PRBool pref; - SECStatus rv; - - suite = ssl_LookupCipherSuiteCfg(which, cipherSuites); - if (suite) { - pref = suite->enabled; - rv = SECSuccess; - } else { - pref = SSL_NOT_ALLOWED; - rv = SECFailure; /* err code was set by Lookup. */ - } - *enabled = pref; - return rv; -} - -SECStatus -ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool enabled) -{ - ssl3CipherSuiteCfg *suite; - - suite = ssl_LookupCipherSuiteCfg(which, ss->cipherSuites); - if (suite == NULL) { - return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */ - } - suite->enabled = enabled; - return SECSuccess; -} - -SECStatus -ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *enabled) -{ - ssl3CipherSuiteCfg *suite; - PRBool pref; - SECStatus rv; - - suite = ssl_LookupCipherSuiteCfg(which, ss->cipherSuites); - if (suite) { - pref = suite->enabled; - rv = SECSuccess; - } else { - pref = SSL_NOT_ALLOWED; - rv = SECFailure; /* err code was set by Lookup. */ - } - *enabled = pref; - return rv; -} - -SECStatus -SSL_SignaturePrefSet(PRFileDesc *fd, const SSLSignatureAndHashAlg *algorithms, - unsigned int count) -{ - sslSocket *ss; - unsigned int i; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SignaturePrefSet", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (!count || count > MAX_SIGNATURE_ALGORITHMS) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ss->ssl3.signatureAlgorithmCount = 0; - for (i = 0; i < count; ++i) { - if (!ssl3_IsSupportedSignatureAlgorithm(&algorithms[i])) { - SSL_DBG(("%d: SSL[%d]: invalid signature algorithm set %d/%d", - SSL_GETPID(), fd, algorithms[i].sigAlg, - algorithms[i].hashAlg)); - continue; - } - - ss->ssl3.signatureAlgorithms[ss->ssl3.signatureAlgorithmCount++] = - algorithms[i]; - } - - if (ss->ssl3.signatureAlgorithmCount == 0) { - PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); - return SECFailure; - } - return SECSuccess; -} - -SECStatus -SSL_SignaturePrefGet(PRFileDesc *fd, SSLSignatureAndHashAlg *algorithms, - unsigned int *count, unsigned int maxCount) -{ - sslSocket *ss; - unsigned int requiredSpace; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SignaturePrefGet", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (!algorithms || !count || - maxCount < ss->ssl3.signatureAlgorithmCount) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - requiredSpace = - ss->ssl3.signatureAlgorithmCount * sizeof(SSLSignatureAndHashAlg); - PORT_Memcpy(algorithms, ss->ssl3.signatureAlgorithms, requiredSpace); - *count = ss->ssl3.signatureAlgorithmCount; - return SECSuccess; -} - -unsigned int -SSL_SignatureMaxCount() -{ - return MAX_SIGNATURE_ALGORITHMS; -} - -SECStatus -ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *ciphers, unsigned int len) -{ - /* |i| iterates over |ciphers| while |done| and |j| iterate over - * |ss->cipherSuites|. */ - unsigned int i, done; - - for (i = done = 0; i < len; i++) { - PRUint16 id = ciphers[i]; - unsigned int existingIndex, j; - PRBool found = PR_FALSE; - - for (j = done; j < ssl_V3_SUITES_IMPLEMENTED; j++) { - if (ss->cipherSuites[j].cipher_suite == id) { - existingIndex = j; - found = PR_TRUE; - break; - } - } - - if (!found) { - continue; - } - - if (existingIndex != done) { - const ssl3CipherSuiteCfg temp = ss->cipherSuites[done]; - ss->cipherSuites[done] = ss->cipherSuites[existingIndex]; - ss->cipherSuites[existingIndex] = temp; - } - done++; - } - - /* Disable all cipher suites that weren't included. */ - for (; done < ssl_V3_SUITES_IMPLEMENTED; done++) { - ss->cipherSuites[done].enabled = 0; - } - - return SECSuccess; -} - -/* copy global default policy into socket. */ -void -ssl3_InitSocketPolicy(sslSocket *ss) -{ - PORT_Memcpy(ss->cipherSuites, cipherSuites, sizeof cipherSuites); - PORT_Memcpy(ss->ssl3.signatureAlgorithms, defaultSignatureAlgorithms, - sizeof(defaultSignatureAlgorithms)); - ss->ssl3.signatureAlgorithmCount = PR_ARRAY_SIZE(defaultSignatureAlgorithms); -} - -SECStatus -ssl3_GetTLSUniqueChannelBinding(sslSocket *ss, - unsigned char *out, - unsigned int *outLen, - unsigned int outLenMax) -{ - PRBool isTLS; - int index = 0; - unsigned int len; - SECStatus rv = SECFailure; - - *outLen = 0; - - ssl_GetSSL3HandshakeLock(ss); - - ssl_GetSpecReadLock(ss); - isTLS = (PRBool)(ss->ssl3.cwSpec->version > SSL_LIBRARY_VERSION_3_0); - ssl_ReleaseSpecReadLock(ss); - - /* The tls-unique channel binding is the first Finished structure in the - * handshake. In the case of a resumption, that's the server's Finished. - * Otherwise, it's the client's Finished. */ - len = ss->ssl3.hs.finishedBytes; - - /* Sending or receiving a Finished message will set finishedBytes to a - * non-zero value. */ - if (len == 0) { - PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); - goto loser; - } - - /* If we are in the middle of a renegotiation then the channel binding - * value is poorly defined and depends on the direction that it will be - * used on. Therefore we simply return an error in this case. */ - if (ss->firstHsDone && ss->ssl3.hs.ws != idle_handshake) { - PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); - goto loser; - } - - /* If resuming, then we want the second Finished value in the array, which - * is the server's */ - if (ss->ssl3.hs.isResuming) - index = 1; - - *outLen = len; - if (outLenMax < len) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - goto loser; - } - - if (isTLS) { - memcpy(out, &ss->ssl3.hs.finishedMsgs.tFinished[index], len); - } else { - memcpy(out, &ss->ssl3.hs.finishedMsgs.sFinished[index], len); - } - - rv = SECSuccess; - -loser: - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; -} - -/* ssl3_config_match_init must have already been called by - * the caller of this function. - */ -SECStatus -ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, unsigned char *cs, int *size) -{ - int i, count = 0; - - PORT_Assert(ss != 0); - if (!ss) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - *size = 0; - return SECSuccess; - } - if (cs == NULL) { - *size = count_cipher_suites(ss, SSL_ALLOWED, PR_TRUE); - return SECSuccess; - } - - /* ssl3_config_match_init was called by the caller of this function. */ - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (config_match(suite, SSL_ALLOWED, PR_TRUE, &ss->vrange, ss)) { - if (cs != NULL) { - *cs++ = 0x00; - *cs++ = (suite->cipher_suite >> 8) & 0xFF; - *cs++ = suite->cipher_suite & 0xFF; - } - count++; - } - } - *size = count; - return SECSuccess; -} - -/* -** If ssl3 socket has completed the first handshake, and is in idle state, -** then start a new handshake. -** If flushCache is true, the SID cache will be flushed first, forcing a -** "Full" handshake (not a session restart handshake), to be done. -** -** called from SSL_RedoHandshake(), which already holds the handshake locks. -*/ -SECStatus -ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) -{ - sslSessionID *sid = ss->sec.ci.sid; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (!ss->firstHsDone || - ((ss->version >= SSL_LIBRARY_VERSION_3_0) && - ss->ssl3.initialized && - (ss->ssl3.hs.ws != idle_handshake))) { - PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); - return SECFailure; - } - - if (IS_DTLS(ss)) { - dtls_RehandshakeCleanup(ss); - } - - if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) { - PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); - return SECFailure; - } - if (sid && flushCache) { - if (ss->sec.uncache) - ss->sec.uncache(sid); /* remove it from whichever cache it's in. */ - ssl_FreeSID(sid); /* dec ref count and free if zero. */ - ss->sec.ci.sid = NULL; - } - - ssl_GetXmitBufLock(ss); /**************************************/ - - /* start off a new handshake. */ - rv = (ss->sec.isServer) ? ssl3_SendHelloRequest(ss) - : ssl3_SendClientHello(ss, PR_FALSE); - - ssl_ReleaseXmitBufLock(ss); /**************************************/ - return rv; -} - -/* Called from ssl_DestroySocketContents() in sslsock.c */ -void -ssl3_DestroySSL3Info(sslSocket *ss) -{ - - if (ss->ssl3.clientCertificate != NULL) - CERT_DestroyCertificate(ss->ssl3.clientCertificate); - - if (ss->ssl3.clientPrivateKey != NULL) - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - - if (ss->ssl3.channelID) - SECKEY_DestroyPrivateKey(ss->ssl3.channelID); - if (ss->ssl3.channelIDPub) - SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub); - - if (ss->ssl3.peerCertArena != NULL) - ssl3_CleanupPeerCerts(ss); - - if (ss->ssl3.clientCertChain != NULL) { - CERT_DestroyCertificateList(ss->ssl3.clientCertChain); - ss->ssl3.clientCertChain = NULL; - } - -/* clean up handshake */ -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - if (ss->ssl3.hs.hashType == handshake_hash_combo) { - SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE); - MD5_DestroyContext((MD5Context *)ss->ssl3.hs.md5_cx, PR_FALSE); - } else if (ss->ssl3.hs.hashType == handshake_hash_single) { - ss->ssl3.hs.sha_obj->destroy(ss->ssl3.hs.sha_cx, PR_FALSE); - } - } -#endif - if (ss->ssl3.hs.md5) { - PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); - } - if (ss->ssl3.hs.sha) { - PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE); - } - if (ss->ssl3.hs.clientSigAndHash) { - PORT_Free(ss->ssl3.hs.clientSigAndHash); - } - if (ss->ssl3.hs.messages.buf) { - PORT_Free(ss->ssl3.hs.messages.buf); - ss->ssl3.hs.messages.buf = NULL; - ss->ssl3.hs.messages.len = 0; - ss->ssl3.hs.messages.space = 0; - } - - /* free the SSL3Buffer (msg_body) */ - PORT_Free(ss->ssl3.hs.msg_body.buf); - - SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE); - - /* free up the CipherSpecs */ - ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE /*freeSrvName*/); - ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE /*freeSrvName*/); - - /* Destroy the DTLS data */ - if (IS_DTLS(ss)) { - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); - if (ss->ssl3.hs.recvdFragments.buf) { - PORT_Free(ss->ssl3.hs.recvdFragments.buf); - } - } - - /* Destroy TLS 1.3 handshake shares */ - tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares); - - /* Destroy TLS 1.3 keys */ - if (ss->ssl3.hs.xSS) - PK11_FreeSymKey(ss->ssl3.hs.xSS); - if (ss->ssl3.hs.xES) - PK11_FreeSymKey(ss->ssl3.hs.xES); - if (ss->ssl3.hs.trafficSecret) - PK11_FreeSymKey(ss->ssl3.hs.trafficSecret); - if (ss->ssl3.hs.clientFinishedSecret) - PK11_FreeSymKey(ss->ssl3.hs.clientFinishedSecret); - if (ss->ssl3.hs.serverFinishedSecret) - PK11_FreeSymKey(ss->ssl3.hs.serverFinishedSecret); - - if (ss->ssl3.dheGroups) { - PORT_Free(ss->ssl3.dheGroups); - } - - ss->ssl3.initialized = PR_FALSE; - - SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE); -} - -#define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER) - -SECStatus -ssl3_ApplyNSSPolicy(void) -{ - unsigned i; - SECStatus rv; - PRUint32 policy = 0; - - rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy); - if (rv != SECSuccess || !(policy & NSS_USE_POLICY_IN_SSL)) { - return SECSuccess; /* do nothing */ - } - - /* disable every ciphersuite */ - for (i = 1; i < PR_ARRAY_SIZE(cipher_suite_defs); ++i) { - const ssl3CipherSuiteDef *suite = &cipher_suite_defs[i]; - SECOidTag policyOid; - - policyOid = MAP_NULL(kea_defs[suite->key_exchange_alg].oid); - rv = NSS_GetAlgorithmPolicy(policyOid, &policy); - if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL_KX)) { - ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE); - ssl_CipherPolicySet(suite->cipher_suite, SSL_NOT_ALLOWED); - continue; - } - - policyOid = MAP_NULL(bulk_cipher_defs[suite->bulk_cipher_alg].oid); - rv = NSS_GetAlgorithmPolicy(policyOid, &policy); - if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) { - ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE); - ssl_CipherPolicySet(suite->cipher_suite, SSL_NOT_ALLOWED); - continue; - } - - if (bulk_cipher_defs[suite->bulk_cipher_alg].type != type_aead) { - policyOid = MAP_NULL(mac_defs[suite->mac_alg].oid); - rv = NSS_GetAlgorithmPolicy(policyOid, &policy); - if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) { - ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE); - ssl_CipherPolicySet(suite->cipher_suite, - SSL_NOT_ALLOWED); - continue; - } - } - } - - rv = ssl3_ConstrainRangeByPolicy(); - - return rv; -} - -/* End of ssl3con.c */
diff --git a/net/third_party/nss/ssl/ssl3ecc.c b/net/third_party/nss/ssl/ssl3ecc.c deleted file mode 100644 index c8e9d06b..0000000 --- a/net/third_party/nss/ssl/ssl3ecc.c +++ /dev/null
@@ -1,1481 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * SSL3 Protocol - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* ECC code moved here from ssl3con.c */ - -#include "nss.h" -#include "cert.h" -#include "ssl.h" -#include "cryptohi.h" /* for DSAU_ stuff */ -#include "keyhi.h" -#include "secder.h" -#include "secitem.h" - -#include "sslimpl.h" -#include "sslproto.h" -#include "sslerr.h" -#include "prtime.h" -#include "prinrval.h" -#include "prerror.h" -#include "pratom.h" -#include "prthread.h" -#include "prinit.h" - -#include "pk11func.h" -#include "secmod.h" - -#include <stdio.h> - -#ifndef NSS_DISABLE_ECC - -#ifndef PK11_SETATTRS -#define PK11_SETATTRS(x, id, v, l) \ - (x)->type = (id); \ - (x)->pValue = (v); \ - (x)->ulValueLen = (l); -#endif - -#define SSL_GET_SERVER_PUBLIC_KEY(sock, type) \ - (ss->serverCerts[type].serverKeyPair ? ss->serverCerts[type].serverKeyPair->pubKey \ - : NULL) - -#define SSL_IS_CURVE_NEGOTIATED(curvemsk, curveName) \ - ((curveName > ec_noName) && \ - (curveName < ec_pastLastName) && \ - ((1UL << curveName) & curvemsk) != 0) - -static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve); - -#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName)) - -/* Table containing OID tags for elliptic curves named in the - * ECC-TLS IETF draft. - */ -static const SECOidTag ecName2OIDTag[] = { - 0, - SEC_OID_SECG_EC_SECT163K1, /* 1 */ - SEC_OID_SECG_EC_SECT163R1, /* 2 */ - SEC_OID_SECG_EC_SECT163R2, /* 3 */ - SEC_OID_SECG_EC_SECT193R1, /* 4 */ - SEC_OID_SECG_EC_SECT193R2, /* 5 */ - SEC_OID_SECG_EC_SECT233K1, /* 6 */ - SEC_OID_SECG_EC_SECT233R1, /* 7 */ - SEC_OID_SECG_EC_SECT239K1, /* 8 */ - SEC_OID_SECG_EC_SECT283K1, /* 9 */ - SEC_OID_SECG_EC_SECT283R1, /* 10 */ - SEC_OID_SECG_EC_SECT409K1, /* 11 */ - SEC_OID_SECG_EC_SECT409R1, /* 12 */ - SEC_OID_SECG_EC_SECT571K1, /* 13 */ - SEC_OID_SECG_EC_SECT571R1, /* 14 */ - SEC_OID_SECG_EC_SECP160K1, /* 15 */ - SEC_OID_SECG_EC_SECP160R1, /* 16 */ - SEC_OID_SECG_EC_SECP160R2, /* 17 */ - SEC_OID_SECG_EC_SECP192K1, /* 18 */ - SEC_OID_SECG_EC_SECP192R1, /* 19 */ - SEC_OID_SECG_EC_SECP224K1, /* 20 */ - SEC_OID_SECG_EC_SECP224R1, /* 21 */ - SEC_OID_SECG_EC_SECP256K1, /* 22 */ - SEC_OID_SECG_EC_SECP256R1, /* 23 */ - SEC_OID_SECG_EC_SECP384R1, /* 24 */ - SEC_OID_SECG_EC_SECP521R1, /* 25 */ -}; - -static const PRUint16 curve2bits[] = { - 0, /* ec_noName = 0, */ - 163, /* ec_sect163k1 = 1, */ - 163, /* ec_sect163r1 = 2, */ - 163, /* ec_sect163r2 = 3, */ - 193, /* ec_sect193r1 = 4, */ - 193, /* ec_sect193r2 = 5, */ - 233, /* ec_sect233k1 = 6, */ - 233, /* ec_sect233r1 = 7, */ - 239, /* ec_sect239k1 = 8, */ - 283, /* ec_sect283k1 = 9, */ - 283, /* ec_sect283r1 = 10, */ - 409, /* ec_sect409k1 = 11, */ - 409, /* ec_sect409r1 = 12, */ - 571, /* ec_sect571k1 = 13, */ - 571, /* ec_sect571r1 = 14, */ - 160, /* ec_secp160k1 = 15, */ - 160, /* ec_secp160r1 = 16, */ - 160, /* ec_secp160r2 = 17, */ - 192, /* ec_secp192k1 = 18, */ - 192, /* ec_secp192r1 = 19, */ - 224, /* ec_secp224k1 = 20, */ - 224, /* ec_secp224r1 = 21, */ - 256, /* ec_secp256k1 = 22, */ - 256, /* ec_secp256r1 = 23, */ - 384, /* ec_secp384r1 = 24, */ - 521, /* ec_secp521r1 = 25, */ - 65535 /* ec_pastLastName */ -}; - -typedef struct Bits2CurveStr { - PRUint16 bits; - ECName curve; -} Bits2Curve; - -static const Bits2Curve bits2curve[] = { - { 192, ec_secp192r1 /* = 19, fast */ }, - { 160, ec_secp160r2 /* = 17, fast */ }, - { 160, ec_secp160k1 /* = 15, */ }, - { 160, ec_secp160r1 /* = 16, */ }, - { 163, ec_sect163k1 /* = 1, */ }, - { 163, ec_sect163r1 /* = 2, */ }, - { 163, ec_sect163r2 /* = 3, */ }, - { 192, ec_secp192k1 /* = 18, */ }, - { 193, ec_sect193r1 /* = 4, */ }, - { 193, ec_sect193r2 /* = 5, */ }, - { 224, ec_secp224r1 /* = 21, fast */ }, - { 224, ec_secp224k1 /* = 20, */ }, - { 233, ec_sect233k1 /* = 6, */ }, - { 233, ec_sect233r1 /* = 7, */ }, - { 239, ec_sect239k1 /* = 8, */ }, - { 256, ec_secp256r1 /* = 23, fast */ }, - { 256, ec_secp256k1 /* = 22, */ }, - { 283, ec_sect283k1 /* = 9, */ }, - { 283, ec_sect283r1 /* = 10, */ }, - { 384, ec_secp384r1 /* = 24, fast */ }, - { 409, ec_sect409k1 /* = 11, */ }, - { 409, ec_sect409r1 /* = 12, */ }, - { 521, ec_secp521r1 /* = 25, fast */ }, - { 571, ec_sect571k1 /* = 13, */ }, - { 571, ec_sect571r1 /* = 14, */ }, - { 65535, ec_noName } -}; - -typedef struct ECDHEKeyPairStr { - ssl3KeyPair *pair; - int error; /* error code of the call-once function */ - PRCallOnceType once; -} ECDHEKeyPair; - -/* arrays of ECDHE KeyPairs */ -static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName]; - -SECStatus -ssl3_ECName2Params(PLArenaPool *arena, ECName curve, SECKEYECParams *params) -{ - SECOidData *oidData = NULL; - PRUint32 policyFlags = 0; - - if ((curve <= ec_noName) || (curve >= ec_pastLastName) || - ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) { - PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - return SECFailure; - } - - if ((NSS_GetAlgorithmPolicy(ecName2OIDTag[curve], &policyFlags) == - SECSuccess) && - !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) { - PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - return SECFailure; - } - - SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)); - /* - * params->data needs to contain the ASN encoding of an object ID (OID) - * representing the named curve. The actual OID is in - * oidData->oid.data so we simply prepend 0x06 and OID length - */ - params->data[0] = SEC_ASN1_OBJECT_ID; - params->data[1] = oidData->oid.len; - memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); - - return SECSuccess; -} - -ECName -ssl3_PubKey2ECName(SECKEYPublicKey *pubKey) -{ - SECItem oid = { siBuffer, NULL, 0 }; - SECOidData *oidData = NULL; - PRUint32 policyFlags = 0; - ECName i; - SECKEYECParams *params; - - if (pubKey->keyType != ecKey) { - PORT_Assert(0); - return ec_noName; - } - - params = &pubKey->u.ec.DEREncodedParams; - - /* - * params->data needs to contain the ASN encoding of an object ID (OID) - * representing a named curve. Here, we strip away everything - * before the actual OID and use the OID to look up a named curve. - */ - if (params->data[0] != SEC_ASN1_OBJECT_ID) - return ec_noName; - oid.len = params->len - 2; - oid.data = params->data + 2; - if ((oidData = SECOID_FindOID(&oid)) == NULL) - return ec_noName; - if ((NSS_GetAlgorithmPolicy(oidData->offset, &policyFlags) == - SECSuccess) && - !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) { - return ec_noName; - } - for (i = ec_noName + 1; i < ec_pastLastName; i++) { - if (ecName2OIDTag[i] == oidData->offset) - return i; - } - - return ec_noName; -} - -/* Caller must set hiLevel error code. */ -static SECStatus -ssl3_ComputeECDHKeyHash(SSLHashType hashAlg, - SECItem ec_params, SECItem server_ecpoint, - SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes, PRBool bypassPKCS11) -{ - PRUint8 *hashBuf; - PRUint8 *pBuf; - SECStatus rv = SECSuccess; - unsigned int bufLen; - /* - * XXX For now, we only support named curves (the appropriate - * checks are made before this method is called) so ec_params - * takes up only two bytes. ECPoint needs to fit in 256 bytes - * (because the spec says the length must fit in one byte) - */ - PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 1 + 256]; - - bufLen = 2 * SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len; - if (bufLen <= sizeof buf) { - hashBuf = buf; - } else { - hashBuf = PORT_Alloc(bufLen); - if (!hashBuf) { - return SECFailure; - } - } - - memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); - pBuf = hashBuf + SSL3_RANDOM_LENGTH; - memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); - pBuf += SSL3_RANDOM_LENGTH; - memcpy(pBuf, ec_params.data, ec_params.len); - pBuf += ec_params.len; - pBuf[0] = (PRUint8)(server_ecpoint.len); - pBuf += 1; - memcpy(pBuf, server_ecpoint.data, server_ecpoint.len); - pBuf += server_ecpoint.len; - PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - - rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, - bypassPKCS11); - - PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); - PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", - hashes->u.s.md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", - hashes->u.s.sha, SHA1_LENGTH)); - - if (hashBuf != buf) - PORT_Free(hashBuf); - return rv; -} - -/* Called from ssl3_SendClientKeyExchange(). */ -SECStatus -ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) -{ - PK11SymKey *pms = NULL; - SECStatus rv = SECFailure; - PRBool isTLS, isTLS12; - CK_MECHANISM_TYPE target; - SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ - SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - /* Generate ephemeral EC keypair */ - if (svrPubKey->keyType != ecKey) { - PORT_SetError(SEC_ERROR_BAD_KEY); - goto loser; - } - /* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */ - privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, - &pubKey, ss->pkcs11PinArg); - if (!privKey || !pubKey) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - goto loser; - } - PRINT_BUF(50, (ss, "ECDH public value:", - pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len)); - - if (isTLS12) { - target = CKM_TLS12_MASTER_KEY_DERIVE_DH; - } else if (isTLS) { - target = CKM_TLS_MASTER_KEY_DERIVE_DH; - } else { - target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - } - - /* Determine the PMS */ - pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, - CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, - CKD_NULL, NULL, NULL); - - if (pms == NULL) { - SSL3AlertDescription desc = illegal_parameter; - (void)SSL3_SendAlert(ss, alert_fatal, desc); - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - SECKEY_DestroyPrivateKey(privKey); - privKey = NULL; - - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, - pubKey->u.ec.publicValue.len + 1); - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - - rv = ssl3_AppendHandshakeVariable(ss, - pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len, 1); - SECKEY_DestroyPublicKey(pubKey); - pubKey = NULL; - - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); - pms = NULL; - - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - rv = SECSuccess; - -loser: - if (pms) - PK11_FreeSymKey(pms); - if (privKey) - SECKEY_DestroyPrivateKey(privKey); - if (pubKey) - SECKEY_DestroyPublicKey(pubKey); - return rv; -} - -ECName -tls13_GroupForECDHEKeyShare(ssl3KeyPair *pair) -{ - return ssl3_PubKey2ECName(pair->pubKey); -} - -/* This function returns the size of the key_exchange field in - * the KeyShareEntry structure. */ -unsigned int -tls13_SizeOfECDHEKeyShareKEX(ssl3KeyPair *pair) -{ - return 1 + /* Length */ - pair->pubKey->u.ec.publicValue.len; -} - -/* This function encodes the key_exchange field in - * the KeyShareEntry structure. */ -SECStatus -tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, ssl3KeyPair *pair) -{ - const SECItem *publicValue; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - publicValue = &pair->pubKey->u.ec.publicValue; - - return ssl3_AppendHandshakeVariable(ss, publicValue->data, - publicValue->len, 1); -} - -/* -** Called from ssl3_HandleClientKeyExchange() -*/ -SECStatus -ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, - PRUint32 length, - SECKEYPublicKey *srvrPubKey, - SECKEYPrivateKey *srvrPrivKey) -{ - PK11SymKey *pms; - SECStatus rv; - SECKEYPublicKey clntPubKey; - CK_MECHANISM_TYPE target; - PRBool isTLS, isTLS12; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - clntPubKey.keyType = ecKey; - clntPubKey.u.ec.DEREncodedParams.len = - srvrPubKey->u.ec.DEREncodedParams.len; - clntPubKey.u.ec.DEREncodedParams.data = - srvrPubKey->u.ec.DEREncodedParams.data; - - rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, - 1, &b, &length); - if (rv != SECSuccess) { - SEND_ALERT - return SECFailure; /* XXX Who sets the error code?? */ - } - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - if (isTLS12) { - target = CKM_TLS12_MASTER_KEY_DERIVE_DH; - } else if (isTLS) { - target = CKM_TLS_MASTER_KEY_DERIVE_DH; - } else { - target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - } - - /* Determine the PMS */ - pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, - CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, - CKD_NULL, NULL, NULL); - - if (pms == NULL) { - /* last gasp. */ - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); - if (rv != SECSuccess) { - SEND_ALERT - return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ - } - return SECSuccess; -} - -/* -** Take an encoded key share and make a public key out of it. -** returns NULL on error. -*/ -SECKEYPublicKey * -tls13_ImportECDHKeyShare(sslSocket *ss, SSL3Opaque *b, - PRUint32 length, ECName curve) -{ - PLArenaPool *arena = NULL; - SECKEYPublicKey *peerKey = NULL; - SECStatus rv; - SECItem ecPoint = { siBuffer, NULL, 0 }; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - rv = ssl3_ConsumeHandshakeVariable(ss, &ecPoint, 1, &b, &length); - if (rv != SECSuccess) { - tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE, - illegal_parameter); - return NULL; - } - if (length || !ecPoint.len) { - tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE, - illegal_parameter); - return NULL; - } - - /* Fail if the ec point uses compressed representation */ - if (ecPoint.data[0] != EC_POINT_FORM_UNCOMPRESSED) { - tls13_FatalError(ss, SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, - illegal_parameter); - return NULL; - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto no_memory; - } - - peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); - if (peerKey == NULL) { - goto no_memory; - } - - peerKey->arena = arena; - peerKey->keyType = ecKey; - /* Set up the encoded params */ - rv = ssl3_ECName2Params(arena, curve, &peerKey->u.ec.DEREncodedParams); - if (rv != SECSuccess) { - goto no_memory; - } - - /* copy publicValue in peerKey */ - if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ecPoint) != - SECSuccess) { - goto no_memory; - } - peerKey->pkcs11Slot = NULL; - peerKey->pkcs11ID = CK_INVALID_HANDLE; - - return peerKey; - -no_memory: /* no-memory error has already been set. */ - PORT_FreeArena(arena, PR_FALSE); - ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE); - return NULL; -} - -PK11SymKey * -tls13_ComputeECDHSharedKey(sslSocket *ss, - SECKEYPrivateKey *myPrivKey, - SECKEYPublicKey *peerKey) -{ - PK11SymKey *shared; - - /* Determine the PMS */ - shared = PK11_PubDeriveWithKDF(myPrivKey, peerKey, PR_FALSE, NULL, NULL, - CKM_ECDH1_DERIVE, - tls13_GetHkdfMechanism(ss), CKA_DERIVE, 0, - CKD_NULL, NULL, NULL); - - if (!shared) { - ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE); - return NULL; - } - - return shared; -} - -ECName -ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits) -{ - int i; - - for (i = 0; bits2curve[i].curve != ec_noName; i++) { - if (bits2curve[i].bits < requiredECCbits) - continue; - if (SSL_IS_CURVE_NEGOTIATED(curvemsk, bits2curve[i].curve)) { - return bits2curve[i].curve; - } - } - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return ec_noName; -} - -/* find the "weakest link". Get strength of signature key and of sym key. - * choose curve for the weakest of those two. - */ -ECName -ssl3_GetCurveNameForServerSocket(sslSocket *ss) -{ - SECKEYPublicKey *svrPublicKey = NULL; - ECName ec_curve = ec_noName; - int signatureKeyStrength = 521; - int requiredECCbits = ss->sec.secretKeyBits * 2; - - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) { - svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh); - if (svrPublicKey) - ec_curve = ssl3_PubKey2ECName(svrPublicKey); - if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, ec_curve)) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return ec_noName; - } - signatureKeyStrength = curve2bits[ec_curve]; - } else { - /* RSA is our signing cert */ - int serverKeyStrengthInBits; - - svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa); - if (!svrPublicKey) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return ec_noName; - } - - /* currently strength in bytes */ - serverKeyStrengthInBits = svrPublicKey->u.rsa.modulus.len; - if (svrPublicKey->u.rsa.modulus.data[0] == 0) { - serverKeyStrengthInBits--; - } - /* convert to strength in bits */ - serverKeyStrengthInBits *= BPB; - - signatureKeyStrength = - SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits); - } - if (requiredECCbits > signatureKeyStrength) - requiredECCbits = signatureKeyStrength; - - return ssl3_GetCurveWithECKeyStrength(ss->ssl3.hs.negotiatedECCurves, - requiredECCbits); -} - -/* function to clear out the lists */ -static SECStatus -ssl3_ShutdownECDHECurves(void *appData, void *nssData) -{ - int i; - ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0]; - - for (i = 0; i < ec_pastLastName; i++, keyPair++) { - if (keyPair->pair) { - ssl3_FreeKeyPair(keyPair->pair); - } - } - memset(gECDHEKeyPairs, 0, sizeof gECDHEKeyPairs); - return SECSuccess; -} - -static PRStatus -ssl3_ECRegister(void) -{ - SECStatus rv; - rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs); - if (rv != SECSuccess) { - gECDHEKeyPairs[ec_noName].error = PORT_GetError(); - } - return (PRStatus)rv; -} - -/* Create an ECDHE key pair for a given curve */ -SECStatus -ssl3_CreateECDHEphemeralKeyPair(ECName ec_curve, ssl3KeyPair **keyPair) -{ - SECKEYPrivateKey *privKey = NULL; - SECKEYPublicKey *pubKey = NULL; - SECKEYECParams ecParams = { siBuffer, NULL, 0 }; - - if (ssl3_ECName2Params(NULL, ec_curve, &ecParams) != SECSuccess) { - return SECFailure; - } - privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL); - SECITEM_FreeItem(&ecParams, PR_FALSE); - - if (!privKey || !pubKey || !(*keyPair = ssl3_NewKeyPair(privKey, pubKey))) { - if (privKey) { - SECKEY_DestroyPrivateKey(privKey); - } - if (pubKey) { - SECKEY_DestroyPublicKey(pubKey); - } - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - return SECFailure; - } - - return SECSuccess; -} - -/* CallOnce function, called once for each named curve. */ -static PRStatus -ssl3_CreateECDHEphemeralKeyPairOnce(void *arg) -{ - ECName ec_curve = (ECName)arg; - ssl3KeyPair *keyPair = NULL; - - PORT_Assert(gECDHEKeyPairs[ec_curve].pair == NULL); - - /* ok, no one has generated a global key for this curve yet, do so */ - if (ssl3_CreateECDHEphemeralKeyPair(ec_curve, &keyPair) != SECSuccess) { - gECDHEKeyPairs[ec_curve].error = PORT_GetError(); - return PR_FAILURE; - } - - gECDHEKeyPairs[ec_curve].pair = keyPair; - return PR_SUCCESS; -} - -/* - * Creates the ephemeral public and private ECDH keys used by - * server in ECDHE_RSA and ECDHE_ECDSA handshakes. - * For now, the elliptic curve is chosen to be the same - * strength as the signing certificate (ECC or RSA). - * We need an API to specify the curve. This won't be a real - * issue until we further develop server-side support for ECC - * cipher suites. - */ -static SECStatus -ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve) -{ - ssl3KeyPair *keyPair = NULL; - - /* if there's no global key for this curve, make one. */ - if (gECDHEKeyPairs[ec_curve].pair == NULL) { - PRStatus status; - - status = PR_CallOnce(&gECDHEKeyPairs[ec_noName].once, ssl3_ECRegister); - if (status != PR_SUCCESS) { - PORT_SetError(gECDHEKeyPairs[ec_noName].error); - return SECFailure; - } - status = PR_CallOnceWithArg(&gECDHEKeyPairs[ec_curve].once, - ssl3_CreateECDHEphemeralKeyPairOnce, - (void *)ec_curve); - if (status != PR_SUCCESS) { - PORT_SetError(gECDHEKeyPairs[ec_curve].error); - return SECFailure; - } - } - - keyPair = gECDHEKeyPairs[ec_curve].pair; - PORT_Assert(keyPair != NULL); - if (!keyPair) - return SECFailure; - ss->ephemeralECDHKeyPair = ssl3_GetKeyPairRef(keyPair); - - return SECSuccess; -} - -SECStatus -ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - PLArenaPool *arena = NULL; - SECKEYPublicKey *peerKey = NULL; - PRBool isTLS, isTLS12; - SECStatus rv; - int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; - SSL3AlertDescription desc = illegal_parameter; - SSL3Hashes hashes; - SECItem signature = { siBuffer, NULL, 0 }; - - SECItem ec_params = { siBuffer, NULL, 0 }; - SECItem ec_point = { siBuffer, NULL, 0 }; - unsigned char paramBuf[3]; /* only for curve_type == named_curve */ - SSLSignatureAndHashAlg sigAndHash; - - sigAndHash.hashAlg = ssl_hash_none; - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - /* XXX This works only for named curves, revisit this when - * we support generic curves. - */ - ec_params.len = sizeof paramBuf; - ec_params.data = paramBuf; - rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - - /* Fail if the curve is not a named curve */ - if ((ec_params.data[0] != ec_type_named) || - (ec_params.data[1] != 0) || - !supportedCurve(ec_params.data[2])) { - errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; - desc = handshake_failure; - goto alert_loser; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - /* Fail if the ec point uses compressed representation */ - if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { - errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; - desc = handshake_failure; - goto alert_loser; - } - - if (isTLS12) { - rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, - &sigAndHash); - if (rv != SECSuccess) { - goto loser; /* malformed or unsupported. */ - } - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( - ss, &sigAndHash, ss->sec.peerCert); - if (rv != SECSuccess) { - goto loser; - } - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - - if (length != 0) { - if (isTLS) - desc = decode_error; - goto alert_loser; /* malformed. */ - } - - PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, - ec_params.len)); - PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); - - /* failures after this point are not malformed handshakes. */ - /* TLS: send decrypt_error if signature failed. */ - desc = isTLS ? decrypt_error : handshake_failure; - - /* - * check to make sure the hash is signed by right guy - */ - rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); - - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, - isTLS, ss->pkcs11PinArg); - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto no_memory; - } - - peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); - if (peerKey == NULL) { - goto no_memory; - } - - peerKey->arena = arena; - peerKey->keyType = ecKey; - - /* set up EC parameters in peerKey */ - if (ssl3_ECName2Params(arena, ec_params.data[2], - &peerKey->u.ec.DEREncodedParams) != - SECSuccess) { - /* we should never get here since we already - * checked that we are dealing with a supported curve - */ - errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; - goto alert_loser; - } - - /* copy publicValue in peerKey */ - if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point)) { - goto no_memory; - } - peerKey->pkcs11Slot = NULL; - peerKey->pkcs11ID = CK_INVALID_HANDLE; - - ss->sec.peerKey = peerKey; - ss->ssl3.hs.ws = wait_cert_request; - - return SECSuccess; - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, desc); -loser: - if (arena) { - PORT_FreeArena(arena, PR_FALSE); - } - PORT_SetError(errCode); - return SECFailure; - -no_memory: /* no-memory error has already been set. */ - if (arena) { - PORT_FreeArena(arena, PR_FALSE); - } - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return SECFailure; -} - -SECStatus -ssl3_SendECDHServerKeyExchange( - sslSocket *ss, - const SSLSignatureAndHashAlg *sigAndHash) -{ - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; - SECStatus rv = SECFailure; - int length; - PRBool isTLS, isTLS12; - SECItem signed_hash = { siBuffer, NULL, 0 }; - SSL3Hashes hashes; - - SECKEYPublicKey *ecdhePub; - SECItem ec_params = { siBuffer, NULL, 0 }; - unsigned char paramBuf[3]; - ECName curve; - SSL3KEAType certIndex; - - /* Generate ephemeral ECDH key pair and send the public key */ - curve = ssl3_GetCurveNameForServerSocket(ss); - if (curve == ec_noName) { - goto loser; - } - - if (ss->opt.reuseServerECDHEKey) { - rv = ssl3_CreateECDHEphemeralKeys(ss, curve); - } else { - rv = ssl3_CreateECDHEphemeralKeyPair(curve, &ss->ephemeralECDHKeyPair); - } - if (rv != SECSuccess) { - goto loser; - } - - ecdhePub = ss->ephemeralECDHKeyPair->pubKey; - PORT_Assert(ecdhePub != NULL); - if (!ecdhePub) { - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - - ec_params.len = sizeof paramBuf; - ec_params.data = paramBuf; - curve = ssl3_PubKey2ECName(ecdhePub); - if (curve != ec_noName) { - ec_params.data[0] = ec_type_named; - ec_params.data[1] = 0x00; - ec_params.data[2] = curve; - } else { - PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - goto loser; - } - - rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg, - ec_params, - ecdhePub->u.ec.publicValue, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - - /* XXX SSLKEAType isn't really a good choice for - * indexing certificates but that's all we have - * for now. - */ - if (kea_def->kea == kea_ecdhe_rsa) - certIndex = kt_rsa; - else /* kea_def->kea == kea_ecdhe_ecdsa */ - certIndex = kt_ecdh; - - rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY, - &signed_hash, isTLS); - if (rv != SECSuccess) { - goto loser; /* ssl3_SignHashes has set err. */ - } - if (signed_hash.data == NULL) { - /* how can this happen and rv == SECSuccess ?? */ - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - - length = ec_params.len + - 1 + ecdhePub->u.ec.publicValue.len + - (isTLS12 ? 2 : 0) + 2 + signed_hash.len; - - rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data, - ecdhePub->u.ec.publicValue.len, 1); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - if (isTLS12) { - rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - } - - rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, - signed_hash.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - PORT_Free(signed_hash.data); - return SECSuccess; - -loser: - if (signed_hash.data != NULL) - PORT_Free(signed_hash.data); - return SECFailure; -} - -/* Lists of ECC cipher suites for searching and disabling. */ - -static const ssl3CipherSuite ecdh_suites[] = { - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_ECDSA_WITH_NULL_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_RSA_WITH_NULL_SHA, - TLS_ECDH_RSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - -static const ssl3CipherSuite ecdh_ecdsa_suites[] = { - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_ECDSA_WITH_NULL_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - -static const ssl3CipherSuite ecdh_rsa_suites[] = { - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_RSA_WITH_NULL_SHA, - TLS_ECDH_RSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - -static const ssl3CipherSuite ecdhe_ecdsa_suites[] = { - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_ECDSA_WITH_NULL_SHA, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - -static const ssl3CipherSuite ecdhe_rsa_suites[] = { - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_RSA_WITH_NULL_SHA, - TLS_ECDHE_RSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - -/* List of all ECC cipher suites */ -static const ssl3CipherSuite ecSuites[] = { - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_ECDSA_WITH_NULL_SHA, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_RSA_WITH_NULL_SHA, - TLS_ECDHE_RSA_WITH_RC4_128_SHA, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_ECDSA_WITH_NULL_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_RSA_WITH_NULL_SHA, - TLS_ECDH_RSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - -/* On this socket, Disable the ECC cipher suites in the argument's list */ -SECStatus -ssl3_DisableECCSuites(sslSocket *ss, const ssl3CipherSuite *suite) -{ - if (!suite) - suite = ecSuites; - for (; *suite; ++suite) { - PORT_CheckSuccess(ssl3_CipherPrefSet(ss, *suite, PR_FALSE)); - } - return SECSuccess; -} - -/* Look at the server certs configured on this socket, and disable any - * ECC cipher suites that are not supported by those certs. - */ -void -ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss) -{ - CERTCertificate *svrCert; - - svrCert = ss->serverCerts[kt_rsa].serverCert; - if (!svrCert) { - ssl3_DisableECCSuites(ss, ecdhe_rsa_suites); - } - - svrCert = ss->serverCerts[kt_ecdh].serverCert; - if (!svrCert) { - ssl3_DisableECCSuites(ss, ecdh_suites); - ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); - } else { - SECOidTag sigTag = SECOID_GetAlgorithmTag(&svrCert->signature); - - switch (sigTag) { - case SEC_OID_PKCS1_RSA_ENCRYPTION: - case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: - ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); - break; - case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: - ssl3_DisableECCSuites(ss, ecdh_rsa_suites); - break; - default: - ssl3_DisableECCSuites(ss, ecdh_suites); - break; - } - } -} - -/* Ask: is ANY ECC cipher suite enabled on this socket? */ -/* Order(N^2). Yuk. Also, this ignores export policy. */ -PRBool -ssl3_IsECCEnabled(sslSocket *ss) -{ - const ssl3CipherSuite *suite; - PK11SlotInfo *slot; - - /* make sure we can do ECC */ - slot = PK11_GetBestSlot(CKM_ECDH1_DERIVE, ss->pkcs11PinArg); - if (!slot) { - return PR_FALSE; - } - PK11_FreeSlot(slot); - - /* make sure an ECC cipher is enabled */ - for (suite = ecSuites; *suite; ++suite) { - PRBool enabled = PR_FALSE; - SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled); - - PORT_Assert(rv == SECSuccess); /* else is coding error */ - if (rv == SECSuccess && enabled) - return PR_TRUE; - } - return PR_FALSE; -} - -#define BE(n) 0, n - -/* Prefabricated TLS client hello extension, Elliptic Curves List, - * offers only 3 curves, the Suite B curves, 23-25 - */ -static const PRUint8 suiteBECList[] = { - 23, 24, 25 -}; - -/* Prefabricated TLS client hello extension, Elliptic Curves List, - * offers curves 1-25. - */ -/* clang-format off */ -static const PRUint8 tlsECList[] = { - 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25 -}; -/* clang-format on */ - -static const PRUint8 ecPtFmt[6] = { - BE(11), /* Extension type */ - BE(2), /* octets that follow */ - 1, /* octets that follow */ - 0 /* uncompressed type only */ -}; - -/* This function already presumes we can do ECC, ssl3_IsECCEnabled must be - * called before this function. It looks to see if we have a token which - * is capable of doing smaller than SuiteB curves. If the token can, we - * presume the token can do the whole SSL suite of curves. If it can't we - * presume the token that allowed ECC to be enabled can only do suite B - * curves. */ -static PRBool -ssl3_SuiteBOnly(sslSocket *ss) -{ - /* See if we can support small curves (like 163). If not, assume we can - * only support Suite-B curves (P-256, P-384, P-521). */ - PK11SlotInfo *slot = - PK11_GetBestSlotWithAttributes(CKM_ECDH1_DERIVE, 0, 163, - ss ? ss->pkcs11PinArg : NULL); - - if (!slot) { - /* nope, presume we can only do suite B */ - return PR_TRUE; - } - /* we can, presume we can do all curves */ - PK11_FreeSlot(slot); - return PR_FALSE; -} - -#define APPEND_CURVE(CURVE_ID) \ - if ((NSS_GetAlgorithmPolicy(ecName2OIDTag[CURVE_ID], &policy) == \ - SECFailure) || \ - (policy & NSS_USE_ALG_IN_SSL_KX)) { \ - enabledCurves[pos++] = 0; \ - enabledCurves[pos++] = CURVE_ID; \ - } - -/* Send our "canned" (precompiled) Supported Elliptic Curves extension, - * which says that we support all TLS-defined named curves. - */ -PRInt32 -ssl3_SendSupportedCurvesXtn( - sslSocket *ss, - PRBool append, - PRUint32 maxBytes) -{ - unsigned char enabledCurves[64]; - PRUint32 policy; - PRInt32 extension_length; - PRInt32 ecListSize = 0; - unsigned int pos = 0; - unsigned int i; - - if (!ss || !ssl3_IsECCEnabled(ss)) - return 0; - - PORT_Assert(sizeof(enabledCurves) > sizeof(tlsECList) * 2); - if (ssl3_SuiteBOnly(ss)) { - for (i = 0; i < sizeof(suiteBECList); i++) { - APPEND_CURVE(suiteBECList[i]); - } - ecListSize = pos; - } else { - for (i = 0; i < sizeof(tlsECList); i++) { - APPEND_CURVE(tlsECList[i]); - } - ecListSize = pos; - } - extension_length = - 2 /* extension type */ + - 2 /* extension length */ + - 2 /* elliptic curves length */ + - ecListSize; - - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_elliptic_curves_xtn, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_AppendHandshakeVariable(ss, enabledCurves, ecListSize, 2); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_elliptic_curves_xtn; - } - } - return extension_length; -} - -PRUint32 -ssl3_GetSupportedECCurveMask(sslSocket *ss) -{ - int i; - PRUint32 curves = 0; - PRUint32 policyFlags = 0; - - PORT_Assert(ec_pastLastName < sizeof(PRUint32) * 8); - - if (ssl3_SuiteBOnly(ss)) { - curves = SSL3_SUITE_B_SUPPORTED_CURVES_MASK; - } else { - curves = SSL3_ALL_SUPPORTED_CURVES_MASK; - } - - for (i = ec_noName + 1; i < ec_pastLastName; i++) { - PRUint32 curve_bit = (1U << i); - if ((curves & curve_bit) && - (NSS_GetAlgorithmPolicy(ecName2OIDTag[i], &policyFlags) == - SECSuccess) && - !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) { - curves &= ~curve_bit; - } - } - return curves; -} - -/* Send our "canned" (precompiled) Supported Point Formats extension, - * which says that we only support uncompressed points. - */ -PRInt32 -ssl3_SendSupportedPointFormatsXtn( - sslSocket *ss, - PRBool append, - PRUint32 maxBytes) -{ - if (!ss || !ssl3_IsECCEnabled(ss)) - return 0; - if (append && maxBytes >= (sizeof ecPtFmt)) { - SECStatus rv = ssl3_AppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt)); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_ec_point_formats_xtn; - } - } - return (sizeof ecPtFmt); -} - -/* Just make sure that the remote client supports uncompressed points, - * Since that is all we support. Disable ECC cipher suites if it doesn't. - */ -SECStatus -ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - int i; - - if (data->len < 2 || data->len > 255 || !data->data || - data->len != (unsigned int)data->data[0] + 1) { - return ssl3_DecodeError(ss); - } - for (i = data->len; --i > 0;) { - if (data->data[i] == 0) { - /* indicate that we should send a reply */ - SECStatus rv; - rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, - &ssl3_SendSupportedPointFormatsXtn); - return rv; - } - } - - /* evil client doesn't support uncompressed */ - ssl3_DisableECCSuites(ss, ecSuites); - return SECSuccess; -} - -#define SSL3_GET_SERVER_PUBLICKEY(sock, type) \ - (ss->serverCerts[type].serverKeyPair ? ss->serverCerts[type].serverKeyPair->pubKey \ - : NULL) - -/* Extract the TLS curve name for the public key in our EC server cert. */ -ECName -ssl3_GetSvrCertCurveName(sslSocket *ss) -{ - SECKEYPublicKey *srvPublicKey; - ECName ec_curve = ec_noName; - - srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh); - if (srvPublicKey) { - ec_curve = ssl3_PubKey2ECName(srvPublicKey); - } - return ec_curve; -} - -/* Ensure that the curve in our server cert is one of the ones supported - * by the remote client, and disable all ECC cipher suites if not. - */ -SECStatus -ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - PRInt32 list_len; - PRUint32 peerCurves = 0; - PRUint32 mutualCurves = 0; - PRUint16 svrCertCurveName; - - if (!data->data || data->len < 4) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* get the length of elliptic_curve_list */ - list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - /* build bit vector of peer's supported curve names */ - while (data->len) { - PRInt32 curve_name = - ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (curve_name < 0) { - return SECFailure; /* fatal alert already sent */ - } - if (curve_name > ec_noName && curve_name < ec_pastLastName) { - peerCurves |= (1U << curve_name); - } - } - /* What curves do we support in common? */ - mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves; - if (!mutualCurves) { - /* no mutually supported EC Curves, disable ECC */ - ssl3_DisableECCSuites(ss, ecSuites); - return SECSuccess; - } - - /* if our ECC cert doesn't use one of these supported curves, - * disable ECC cipher suites that require an ECC cert. - */ - svrCertCurveName = ssl3_GetSvrCertCurveName(ss); - if (svrCertCurveName != ec_noName && - (mutualCurves & (1U << svrCertCurveName)) != 0) { - return SECSuccess; - } - /* Our EC cert doesn't contain a mutually supported curve. - * Disable all ECC cipher suites that require an EC cert - */ - ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); - ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); - return SECSuccess; -} - -#endif /* NSS_DISABLE_ECC */
diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c deleted file mode 100644 index 3b48c9e..0000000 --- a/net/third_party/nss/ssl/ssl3ext.c +++ /dev/null
@@ -1,3290 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * SSL3 Protocol - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* TLS extension code moved here from ssl3ecc.c */ - -#include "nssrenam.h" -#include "nss.h" -#include "ssl.h" -#include "sslproto.h" -#include "sslimpl.h" -#include "pk11pub.h" -#ifdef NO_PKCS11_BYPASS -#include "blapit.h" -#else -#include "blapi.h" -#endif -#include "prinit.h" - -static unsigned char key_name[SESS_TICKET_KEY_NAME_LEN]; -static PK11SymKey *session_ticket_enc_key_pkcs11 = NULL; -static PK11SymKey *session_ticket_mac_key_pkcs11 = NULL; - -#ifndef NO_PKCS11_BYPASS -static unsigned char session_ticket_enc_key[AES_256_KEY_LENGTH]; -static unsigned char session_ticket_mac_key[SHA256_LENGTH]; - -static PRBool session_ticket_keys_initialized = PR_FALSE; -#endif -static PRCallOnceType generate_session_keys_once; - -/* forward static function declarations */ -static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss, - SECItem *data, EncryptedSessionTicket *enc_session_ticket); -static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, - PRUint32 bytes); -static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, - PRInt32 lenSize); -static SECStatus ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, - PK11SymKey **aes_key, PK11SymKey **mac_key); -#ifndef NO_PKCS11_BYPASS -static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, - PRUint32 *aes_key_length, const unsigned char **mac_key, - PRUint32 *mac_key_length); -#endif -static PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket *ss, - PRBool append, PRUint32 maxBytes); -static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -static SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -static SECStatus ssl3_ClientHandleAppProtoXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -static SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -static SECStatus ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); -static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static PRInt32 ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static PRInt32 ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static PRInt32 ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static PRInt32 ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static SECStatus ssl3_ClientHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); -static SECStatus ssl3_ServerHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); -static SECStatus ssl3_ClientHandleChannelIDXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -static PRInt32 ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static PRInt32 ssl3_ServerSendStatusRequestXtn(sslSocket *ss, - PRBool append, PRUint32 maxBytes); -static SECStatus ssl3_ServerHandleStatusRequestXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -static SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); -static PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); - -static PRInt32 ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, - PRBool append, - PRUint32 maxBytes); -static SECStatus ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); -static PRInt32 ssl3_ServerSendSignedCertTimestampXtn(sslSocket *ss, - PRBool append, - PRUint32 maxBytes); -static SECStatus ssl3_ServerHandleSignedCertTimestampXtn(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); -static PRInt32 ssl3_ClientSendDraftVersionXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static SECStatus ssl3_ServerHandleDraftVersionXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data); -static PRInt32 ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static SECStatus ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); -static PRInt32 tls13_ClientSendKeyShareXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -static SECStatus tls13_ClientHandleKeyShareXtn(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); -static SECStatus tls13_ServerHandleKeyShareXtn(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); - -/* - * Write bytes. Using this function means the SECItem structure - * cannot be freed. The caller is expected to call this function - * on a shallow copy of the structure. - */ -static SECStatus -ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes) -{ - if (bytes > item->len) - return SECFailure; - - PORT_Memcpy(item->data, buf, bytes); - item->data += bytes; - item->len -= bytes; - return SECSuccess; -} - -/* - * Write a number in network byte order. Using this function means the - * SECItem structure cannot be freed. The caller is expected to call - * this function on a shallow copy of the structure. - */ -static SECStatus -ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize) -{ - SECStatus rv; - PRUint8 b[4]; - PRUint8 *p = b; - - switch (lenSize) { - case 4: - *p++ = (PRUint8)(num >> 24); - case 3: - *p++ = (PRUint8)(num >> 16); - case 2: - *p++ = (PRUint8)(num >> 8); - case 1: - *p = (PRUint8)num; - } - rv = ssl3_AppendToItem(item, &b[0], lenSize); - return rv; -} - -static SECStatus -ssl3_SessionTicketShutdown(void *appData, void *nssData) -{ - if (session_ticket_enc_key_pkcs11) { - PK11_FreeSymKey(session_ticket_enc_key_pkcs11); - session_ticket_enc_key_pkcs11 = NULL; - } - if (session_ticket_mac_key_pkcs11) { - PK11_FreeSymKey(session_ticket_mac_key_pkcs11); - session_ticket_mac_key_pkcs11 = NULL; - } - PORT_Memset(&generate_session_keys_once, 0, - sizeof(generate_session_keys_once)); - return SECSuccess; -} - -static PRStatus -ssl3_GenerateSessionTicketKeysPKCS11(void *data) -{ - SECStatus rv; - sslSocket *ss = (sslSocket *)data; - SECKEYPrivateKey *svrPrivKey = ss->serverCerts[kt_rsa].SERVERKEY; - SECKEYPublicKey *svrPubKey = ss->serverCerts[kt_rsa].serverKeyPair->pubKey; - - if (svrPrivKey == NULL || svrPubKey == NULL) { - SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.", - SSL_GETPID(), ss->fd)); - goto loser; - } - - /* Get a copy of the session keys from shared memory. */ - PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, - sizeof(SESS_TICKET_KEY_NAME_PREFIX)); - if (!ssl_GetSessionTicketKeysPKCS11(svrPrivKey, svrPubKey, - ss->pkcs11PinArg, &key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN], - &session_ticket_enc_key_pkcs11, &session_ticket_mac_key_pkcs11)) - return PR_FAILURE; - - rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL); - if (rv != SECSuccess) - goto loser; - - return PR_SUCCESS; - -loser: - ssl3_SessionTicketShutdown(NULL, NULL); - return PR_FAILURE; -} - -static SECStatus -ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, PK11SymKey **aes_key, - PK11SymKey **mac_key) -{ - if (PR_CallOnceWithArg(&generate_session_keys_once, - ssl3_GenerateSessionTicketKeysPKCS11, ss) != - PR_SUCCESS) - return SECFailure; - - if (session_ticket_enc_key_pkcs11 == NULL || - session_ticket_mac_key_pkcs11 == NULL) - return SECFailure; - - *aes_key = session_ticket_enc_key_pkcs11; - *mac_key = session_ticket_mac_key_pkcs11; - return SECSuccess; -} - -#ifndef NO_PKCS11_BYPASS -static PRStatus -ssl3_GenerateSessionTicketKeys(void) -{ - PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, - sizeof(SESS_TICKET_KEY_NAME_PREFIX)); - - if (!ssl_GetSessionTicketKeys(&key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN], - session_ticket_enc_key, session_ticket_mac_key)) - return PR_FAILURE; - - session_ticket_keys_initialized = PR_TRUE; - return PR_SUCCESS; -} - -static SECStatus -ssl3_GetSessionTicketKeys(const unsigned char **aes_key, - PRUint32 *aes_key_length, const unsigned char **mac_key, - PRUint32 *mac_key_length) -{ - if (PR_CallOnce(&generate_session_keys_once, - ssl3_GenerateSessionTicketKeys) != PR_SUCCESS) - return SECFailure; - - if (!session_ticket_keys_initialized) - return SECFailure; - - *aes_key = session_ticket_enc_key; - *aes_key_length = sizeof(session_ticket_enc_key); - *mac_key = session_ticket_mac_key; - *mac_key_length = sizeof(session_ticket_mac_key); - - return SECSuccess; -} -#endif - -/* Table of handlers for received TLS hello extensions, one per extension. - * In the second generation, this table will be dynamic, and functions - * will be registered here. - */ -/* This table is used by the server, to handle client hello extensions. */ -static const ssl3HelloExtensionHandler clientHelloHandlers[] = { - { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, -#ifndef NSS_DISABLE_ECC - { ssl_elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn }, - { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, -#endif - { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, - { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, - { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, - { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn }, - { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn }, - { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, - { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, - { ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn }, - { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, - { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn }, - { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn }, - { -1, NULL } -}; - -/* These two tables are used by the client, to handle server hello - * extensions. */ -static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { - { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, - /* TODO: add a handler for ssl_ec_point_formats_xtn */ - { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, - { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, - { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, - { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn }, - { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn }, - { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, - { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, - { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, - { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn }, - { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn }, - { -1, NULL } -}; - -static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = { - { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, - { -1, NULL } -}; - -/* Tables of functions to format TLS hello extensions, one function per - * extension. - * These static tables are for the formatting of client hello extensions. - * The server's table of hello senders is dynamic, in the socket struct, - * and sender functions are registered there. - */ -static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = - { - { ssl_server_name_xtn, &ssl3_SendServerNameXtn }, - { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn }, - { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, -#ifndef NSS_DISABLE_ECC - { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, - { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, -#endif - { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, - { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, - { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn }, - { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn }, - { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, - { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, - { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn }, - { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn }, - { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn }, - /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will - * time out or terminate the connection if the last extension in the - * client hello is empty. They are not intolerant of TLS 1.2, so list - * signature_algorithms at the end. See bug 1243641. */ - { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, - /* any extra entries will appear as { 0, NULL } */ - }; - -static const ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = - { - { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn } - /* any extra entries will appear as { 0, NULL } */ - }; - -static PRBool -arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type) -{ - unsigned int i; - for (i = 0; i < len; i++) { - if (ex_type == array[i]) - return PR_TRUE; - } - return PR_FALSE; -} - -PRBool -ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type) -{ - TLSExtensionData *xtnData = &ss->xtnData; - return arrayContainsExtension(xtnData->negotiated, - xtnData->numNegotiated, ex_type); -} - -static PRBool -ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) -{ - TLSExtensionData *xtnData = &ss->xtnData; - return arrayContainsExtension(xtnData->advertised, - xtnData->numAdvertised, ex_type); -} - -/* Format an SNI extension, using the name from the socket's URL, - * unless that name is a dotted decimal string. - * Used by client and server. - */ -PRInt32 -ssl3_SendServerNameXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - SECStatus rv; - if (!ss) - return 0; - if (!ss->sec.isServer) { - PRUint32 len; - PRNetAddr netAddr; - - /* must have a hostname */ - if (!ss->url || !ss->url[0]) - return 0; - /* must not be an IPv4 or IPv6 address */ - if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { - /* is an IP address (v4 or v6) */ - return 0; - } - len = PORT_Strlen(ss->url); - if (append && maxBytes >= len + 9) { - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); - if (rv != SECSuccess) - return -1; - /* length of server_name_list */ - rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); - if (rv != SECSuccess) - return -1; - /* Name Type (sni_host_name) */ - rv = ssl3_AppendHandshake(ss, "\0", 1); - if (rv != SECSuccess) - return -1; - /* HostName (length and value) */ - rv = ssl3_AppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_server_name_xtn; - } - } - return len + 9; - } - /* Server side */ - if (append && maxBytes >= 4) { - rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - } - return 4; -} - -/* handle an incoming SNI extension, by ignoring it. */ -SECStatus -ssl3_HandleServerNameXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECItem *names = NULL; - PRUint32 listCount = 0, namesPos = 0, i; - TLSExtensionData *xtnData = &ss->xtnData; - SECItem ldata; - PRInt32 listLenBytes = 0; - - if (!ss->sec.isServer) { - return SECSuccess; /* ignore extension */ - } - - /* Server side - consume client data and register server sender. */ - /* do not parse the data if don't have user extension handling function. */ - if (!ss->sniSocketConfig) { - return SECSuccess; - } - /* length of server_name_list */ - listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (listLenBytes < 0) { - return SECFailure; - } - if (listLenBytes == 0 || listLenBytes != data->len) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - ldata = *data; - /* Calculate the size of the array.*/ - while (listLenBytes > 0) { - SECItem litem; - SECStatus rv; - PRInt32 type; - /* Skip Name Type (sni_host_name); checks are on the second pass */ - type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len); - if (type < 0) { /* i.e., SECFailure cast to PRint32 */ - return SECFailure; - } - rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len); - if (rv != SECSuccess) { - return rv; - } - /* Adjust total length for consumed item, item len and type.*/ - listLenBytes -= litem.len + 3; - if (listLenBytes > 0 && !ldata.len) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - listCount += 1; - } - names = PORT_ZNewArray(SECItem, listCount); - if (!names) { - return SECFailure; - } - for (i = 0; i < listCount; i++) { - unsigned int j; - PRInt32 type; - SECStatus rv; - PRBool nametypePresent = PR_FALSE; - /* Name Type (sni_host_name) */ - type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len); - /* Check if we have such type in the list */ - for (j = 0; j < listCount && names[j].data; j++) { - /* TODO bug 998524: .type is not assigned a value */ - if (names[j].type == type) { - nametypePresent = PR_TRUE; - break; - } - } - /* HostName (length and value) */ - rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2, - &data->data, &data->len); - if (rv != SECSuccess) { - PORT_Assert(0); - PORT_Free(names); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return rv; - } - if (nametypePresent == PR_FALSE) { - namesPos += 1; - } - } - /* Free old and set the new data. */ - if (xtnData->sniNameArr) { - PORT_Free(ss->xtnData.sniNameArr); - } - xtnData->sniNameArr = names; - xtnData->sniNameArrSize = namesPos; - xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn; - - return SECSuccess; -} - -/* Called by both clients and servers. - * Clients sends a filled in session ticket if one is available, and otherwise - * sends an empty ticket. Servers always send empty tickets. - */ -PRInt32 -ssl3_SendSessionTicketXtn( - sslSocket *ss, - PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length; - NewSessionTicket *session_ticket = NULL; - sslSessionID *sid = ss->sec.ci.sid; - - /* Ignore the SessionTicket extension if processing is disabled. */ - if (!ss->opt.enableSessionTickets) - return 0; - - /* Empty extension length = extension_type (2-bytes) + - * length(extension_data) (2-bytes) - */ - extension_length = 4; - - /* If we are a client then send a session ticket if one is availble. - * Servers that support the extension and are willing to negotiate the - * the extension always respond with an empty extension. - */ - if (!ss->sec.isServer) { - /* The caller must be holding sid->u.ssl3.lock for reading. We cannot - * just acquire and release the lock within this function because the - * caller will call this function twice, and we need the inputs to be - * consistent between the two calls. Note that currently the caller - * will only be holding the lock when we are the client and when we're - * attempting to resume an existing session. - */ - - session_ticket = &sid->u.ssl3.locked.sessionTicket; - if (session_ticket->ticket.data) { - if (ss->xtnData.ticketTimestampVerified) { - extension_length += session_ticket->ticket.len; - } else if (!append && - (session_ticket->ticket_lifetime_hint == 0 || - (session_ticket->ticket_lifetime_hint + - session_ticket->received_timestamp > - ssl_Time()))) { - extension_length += session_ticket->ticket.len; - ss->xtnData.ticketTimestampVerified = PR_TRUE; - } - } - } - - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2); - if (rv != SECSuccess) - goto loser; - if (session_ticket && session_ticket->ticket.data && - ss->xtnData.ticketTimestampVerified) { - rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data, - session_ticket->ticket.len, 2); - ss->xtnData.ticketTimestampVerified = PR_FALSE; - ss->xtnData.sentSessionTicketInClientHello = PR_TRUE; - } else { - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - } - if (rv != SECSuccess) - goto loser; - - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_session_ticket_xtn; - } - } - return extension_length; - -loser: - ss->xtnData.ticketTimestampVerified = PR_FALSE; - return -1; -} - -/* handle an incoming Next Protocol Negotiation extension. */ -static SECStatus -ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - if (ss->firstHsDone || data->len != 0) { - /* Clients MUST send an empty NPN extension, if any. */ - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); - return SECFailure; - } - - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - - /* TODO: server side NPN support would require calling - * ssl3_RegisterServerHelloExtensionSender here in order to echo the - * extension back to the client. */ - - return SECSuccess; -} - -/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: none - * of the lengths may be 0 and the sum of the lengths must equal the length of - * the block. */ -SECStatus -ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length) -{ - unsigned int offset = 0; - - while (offset < length) { - unsigned int newOffset = offset + 1 + (unsigned int)data[offset]; - /* Reject embedded nulls to protect against buggy applications that - * store protocol identifiers in null-terminated strings. - */ - if (newOffset > length || data[offset] == 0) { - return SECFailure; - } - offset = newOffset; - } - - return SECSuccess; -} - -/* protocol selection handler for ALPN (server side) and NPN (client side) */ -static SECStatus -ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - unsigned char resultBuffer[255]; - SECItem result = { siBuffer, resultBuffer, 0 }; - - rv = ssl3_ValidateNextProtoNego(data->data, data->len); - if (rv != SECSuccess) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); - return rv; - } - - PORT_Assert(ss->nextProtoCallback); - /* For ALPN, the cipher suite isn't selected yet. Note that extensions - * sometimes affect what cipher suite is selected, e.g., for ECC. */ - PORT_Assert((ss->ssl3.hs.preliminaryInfo & - ssl_preinfo_all & ~ssl_preinfo_cipher_suite) == - (ssl_preinfo_all & ~ssl_preinfo_cipher_suite)); - rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len, - result.data, &result.len, sizeof(resultBuffer)); - if (rv != SECSuccess) { - /* Expect callback to call PORT_SetError() */ - (void)SSL3_SendAlert(ss, alert_fatal, internal_error); - return SECFailure; - } - - /* If the callback wrote more than allowed to |result| it has corrupted our - * stack. */ - if (result.len > sizeof(resultBuffer)) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - /* TODO: crash */ - return SECFailure; - } - - SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE); - - if (ex_type == ssl_app_layer_protocol_xtn && - ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) { - /* The callback might say OK, but then it picks a default value - one - * that was not listed. That's OK for NPN, but not ALPN. */ - (void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL); - return SECFailure; - } - - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result); -} - -/* handle an incoming ALPN extension at the server */ -static SECStatus -ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - int count; - SECStatus rv; - - /* We expressly don't want to allow ALPN on renegotiation, - * despite it being permitted by the spec. */ - if (ss->firstHsDone || data->len == 0) { - /* Clients MUST send a non-empty ALPN extension. */ - (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); - return SECFailure; - } - - /* Unlike NPN, ALPN has extra redundant length information so that - * the extension is the same in both ClientHello and ServerHello. */ - count = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (count != data->len) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - if (!ss->nextProtoCallback) { - /* we're not configured for it */ - return SECSuccess; - } - - rv = ssl3_SelectAppProtocol(ss, ex_type, data); - if (rv != SECSuccess) { - return rv; - } - - /* prepare to send back a response, if we negotiated */ - if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) { - rv = ssl3_RegisterServerHelloExtensionSender( - ss, ex_type, ssl3_ServerSendAppProtoXtn); - if (rv != SECSuccess) { - (void)SSL3_SendAlert(ss, alert_fatal, internal_error); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return rv; - } - } - return SECSuccess; -} - -static SECStatus -ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - PORT_Assert(!ss->firstHsDone); - - if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) { - /* If the server negotiated ALPN then it has already told us what - * protocol to use, so it doesn't make sense for us to try to negotiate - * a different one by sending the NPN handshake message. However, if - * we've negotiated NPN then we're required to send the NPN handshake - * message. Thus, these two extensions cannot both be negotiated on the - * same connection. */ - (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - PORT_SetError(SSL_ERROR_BAD_SERVER); - return SECFailure; - } - - /* We should only get this call if we sent the extension, so - * ss->nextProtoCallback needs to be non-NULL. However, it is possible - * that an application erroneously cleared the callback between the time - * we sent the ClientHello and now. */ - if (!ss->nextProtoCallback) { - PORT_Assert(0); - (void)SSL3_SendAlert(ss, alert_fatal, internal_error); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK); - return SECFailure; - } - - return ssl3_SelectAppProtocol(ss, ex_type, data); -} - -static SECStatus -ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - PRInt32 list_len; - SECItem protocol_name; - - if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - /* The extension data from the server has the following format: - * uint16 name_list_len; - * uint8 len; // where len >= 1 - * uint8 protocol_name[len]; */ - if (data->len < 4 || data->len > 2 + 1 + 255) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); - return SECFailure; - } - - list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - /* The list has to be the entire extension. */ - if (list_len != data->len) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); - return SECFailure; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &protocol_name, 1, - &data->data, &data->len); - /* The list must have exactly one value. */ - if (rv != SECSuccess || data->len != 0) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); - return SECFailure; - } - - SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE); - ss->ssl3.nextProtoState = SSL_NEXT_PROTO_SELECTED; - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &protocol_name); -} - -static PRInt32 -ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length; - - /* Renegotiations do not send this extension. */ - if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) { - return 0; - } - - extension_length = 4; - - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_next_proto_nego_xtn; - } - - return extension_length; - -loser: - return -1; -} - -static PRInt32 -ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) -{ - PRInt32 extension_length; - unsigned char *alpn_protos = NULL; - - /* Renegotiations do not send this extension. */ - if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) { - return 0; - } - - extension_length = 2 /* extension type */ + 2 /* extension length */ + - 2 /* protocol name list length */ + - ss->opt.nextProtoNego.len; - - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - /* NPN requires that the client's fallback protocol is first in the - * list. However, ALPN sends protocols in preference order. So we - * allocate a buffer and move the first protocol to the end of the - * list. */ - SECStatus rv; - const unsigned int len = ss->opt.nextProtoNego.len; - - alpn_protos = PORT_Alloc(len); - if (alpn_protos == NULL) { - return SECFailure; - } - if (len > 0) { - /* Each protocol string is prefixed with a single byte length. */ - unsigned int i = ss->opt.nextProtoNego.data[0] + 1; - if (i <= len) { - memcpy(alpn_protos, &ss->opt.nextProtoNego.data[i], len - i); - memcpy(alpn_protos + len - i, ss->opt.nextProtoNego.data, i); - } else { - /* This seems to be invalid data so we'll send as-is. */ - memcpy(alpn_protos, ss->opt.nextProtoNego.data, len); - } - } - - rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); - if (rv != SECSuccess) { - goto loser; - } - rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) { - goto loser; - } - rv = ssl3_AppendHandshakeVariable(ss, alpn_protos, len, 2); - PORT_Free(alpn_protos); - alpn_protos = NULL; - if (rv != SECSuccess) { - goto loser; - } - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_app_layer_protocol_xtn; - } - - return extension_length; - -loser: - if (alpn_protos) { - PORT_Free(alpn_protos); - } - return -1; -} - -static PRInt32 -ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) -{ - PRInt32 extension_length; - - /* we're in over our heads if any of these fail */ - PORT_Assert(ss->opt.enableALPN); - PORT_Assert(ss->ssl3.nextProto.data); - PORT_Assert(ss->ssl3.nextProto.len > 0); - PORT_Assert(ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED); - PORT_Assert(!ss->firstHsDone); - - extension_length = 2 /* extension type */ + 2 /* extension length */ + - 2 /* protocol name list */ + 1 /* name length */ + - ss->ssl3.nextProto.len; - - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.nextProto.len + 1, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data, - ss->ssl3.nextProto.len, 1); - if (rv != SECSuccess) { - return -1; - } - } - - return extension_length; -} - -static SECStatus -ssl3_ClientHandleChannelIDXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - PORT_Assert(ss->getChannelID != NULL); - - if (data->len) { - PORT_SetError(SSL_ERROR_BAD_CHANNEL_ID_DATA); - return SECFailure; - } - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - return SECSuccess; -} - -static PRInt32 -ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length = 4; - - if (!ss->getChannelID) - return 0; - - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (ss->sec.ci.sid->cached != never_cached && - ss->sec.ci.sid->u.ssl3.originalHandshakeHash.len == 0) { - /* We can't do ChannelID on a connection if we're resuming and didn't - * do ChannelID on the original connection: without ChannelID on the - * original connection we didn't record the handshake hashes needed for - * the signature. */ - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_channel_id_xtn; - } - - return extension_length; - -loser: - return -1; -} - -static SECStatus -ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - /* The echoed extension must be empty. */ - if (data->len != 0) { - return SECSuccess; /* Ignore the extension. */ - } - - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - - return SECSuccess; -} - -static PRInt32 -ssl3_ServerSendStatusRequestXtn( - sslSocket *ss, - PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length; - SSLKEAType effectiveExchKeyType; - SECStatus rv; - - /* ssl3_SendCertificateStatus (which sents the certificate status data) - * uses the exact same logic to select the server certificate - * and determine if we have the status for that certificate. */ - - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa || - ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) { - effectiveExchKeyType = ssl_kea_rsa; - } else { - effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; - } - - if (!ss->certStatusArray[effectiveExchKeyType] || - !ss->certStatusArray[effectiveExchKeyType]->len) { - return 0; - } - - extension_length = 2 + 2; - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - /* The certificate status data is sent in ssl3_SendCertificateStatus. */ - } - - return extension_length; -} - -/* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the - * client side. See RFC 4366 section 3.6. */ -static PRInt32 -ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length; - - if (!ss->opt.enableOCSPStapling) - return 0; - - /* extension_type (2-bytes) + - * length(extension_data) (2-bytes) + - * status_type (1) + - * responder_id_list length (2) + - * request_extensions length (2) - */ - extension_length = 9; - - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - if (append) { - SECStatus rv; - TLSExtensionData *xtnData; - - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_AppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1); - if (rv != SECSuccess) - return -1; - /* A zero length responder_id_list means that the responders are - * implicitly known to the server. */ - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - /* A zero length request_extensions means that there are no extensions. - * Specifically, we don't set the id-pkix-ocsp-nonce extension. This - * means that the server can replay a cached OCSP response to us. */ - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - - xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn; - } - return extension_length; -} - -/* - * NewSessionTicket - * Called from ssl3_HandleFinished - */ -SECStatus -ssl3_SendNewSessionTicket(sslSocket *ss) -{ - PRUint32 i; - SECStatus rv; - NewSessionTicket ticket; - SECItem plaintext; - SECItem plaintext_item = { 0, NULL, 0 }; - SECItem ciphertext = { 0, NULL, 0 }; - PRUint32 ciphertext_length; - PRBool ms_is_wrapped; - unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; - SECItem ms_item = { 0, NULL, 0 }; - SSL3KEAType effectiveExchKeyType = ssl_kea_null; - PRUint32 padding_length; - PRUint32 message_length; - PRUint32 cert_length = 0; - PRUint8 length_buf[4]; - PRUint32 now; - PK11SymKey *aes_key_pkcs11; - PK11SymKey *mac_key_pkcs11; -#ifndef NO_PKCS11_BYPASS - const unsigned char *aes_key; - const unsigned char *mac_key; - PRUint32 aes_key_length; - PRUint32 mac_key_length; - PRUint64 aes_ctx_buf[MAX_CIPHER_CONTEXT_LLONGS]; - AESContext *aes_ctx; - const SECHashObject *hashObj = NULL; - PRUint64 hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS]; - HMACContext *hmac_ctx; -#endif - CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC; - PK11Context *aes_ctx_pkcs11; - CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC; - PK11Context *hmac_ctx_pkcs11 = NULL; - unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; - unsigned int computed_mac_length; - unsigned char iv[AES_BLOCK_SIZE]; - SECItem ivItem; - SECItem *srvName = NULL; - PRUint32 srvNameLen = 0; - CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, - * must be >= 0 */ - - SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT; - if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - cert_length = 3 + ss->sec.ci.sid->peerCert->derCert.len; - } - - /* Get IV and encryption keys */ - ivItem.data = iv; - ivItem.len = sizeof(iv); - rv = PK11_GenerateRandom(iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length, - &mac_key, &mac_key_length); - } else -#endif - { - rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11, - &mac_key_pkcs11); - } - if (rv != SECSuccess) - goto loser; - - if (ss->ssl3.pwSpec->msItem.len && ss->ssl3.pwSpec->msItem.data) { - /* The master secret is available unwrapped. */ - ms_item.data = ss->ssl3.pwSpec->msItem.data; - ms_item.len = ss->ssl3.pwSpec->msItem.len; - ms_is_wrapped = PR_FALSE; - } else { - /* Extract the master secret wrapped. */ - sslSessionID sid; - PORT_Memset(&sid, 0, sizeof(sslSessionID)); - - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa || - ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) { - effectiveExchKeyType = kt_rsa; - } else { - effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; - } - - rv = ssl3_CacheWrappedMasterSecret(ss, &sid, ss->ssl3.pwSpec, - effectiveExchKeyType); - if (rv == SECSuccess) { - if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) - goto loser; - memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret, - sid.u.ssl3.keys.wrapped_master_secret_len); - ms_item.data = wrapped_ms; - ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len; - msWrapMech = sid.u.ssl3.masterWrapMech; - } else { - /* TODO: else send an empty ticket. */ - goto loser; - } - ms_is_wrapped = PR_TRUE; - } - /* Prep to send negotiated name */ - srvName = &ss->ssl3.pwSpec->srvVirtName; - if (srvName->data && srvName->len) { - srvNameLen = 2 + srvName->len; /* len bytes + name len */ - } - - ciphertext_length = - sizeof(PRUint16) /* ticket_version */ - + sizeof(SSL3ProtocolVersion) /* ssl_version */ - + sizeof(ssl3CipherSuite) /* ciphersuite */ - + 1 /* compression */ - + 10 /* cipher spec parameters */ - + 1 /* SessionTicket.ms_is_wrapped */ - + 1 /* effectiveExchKeyType */ - + 4 /* msWrapMech */ - + 2 /* master_secret.length */ - + ms_item.len /* master_secret */ - + 1 /* client_auth_type */ - + cert_length /* cert */ - + 1 /* server name type */ - + srvNameLen /* name len + length field */ - + 1 /* extendedMasterSecretUsed */ - + sizeof(ticket.ticket_lifetime_hint); - padding_length = AES_BLOCK_SIZE - - (ciphertext_length % - AES_BLOCK_SIZE); - ciphertext_length += padding_length; - - message_length = - sizeof(ticket.ticket_lifetime_hint) /* ticket_lifetime_hint */ - + 2 /* length field for NewSessionTicket.ticket */ - + SESS_TICKET_KEY_NAME_LEN /* key_name */ - + AES_BLOCK_SIZE /* iv */ - + 2 /* length field for NewSessionTicket.ticket.encrypted_state */ - + ciphertext_length /* encrypted_state */ - + TLS_EX_SESS_TICKET_MAC_LENGTH; /* mac */ - - if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL) - goto loser; - - plaintext = plaintext_item; - - /* ticket_version */ - rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, - sizeof(PRUint16)); - if (rv != SECSuccess) - goto loser; - - /* ssl_version */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->version, - sizeof(SSL3ProtocolVersion)); - if (rv != SECSuccess) - goto loser; - - /* ciphersuite */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite, - sizeof(ssl3CipherSuite)); - if (rv != SECSuccess) - goto loser; - - /* compression */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1); - if (rv != SECSuccess) - goto loser; - - /* cipher spec parameters */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authAlgorithm, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4); - if (rv != SECSuccess) - goto loser; - - /* master_secret */ - rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, effectiveExchKeyType, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len); - if (rv != SECSuccess) - goto loser; - - /* client_identity */ - if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, - ss->sec.ci.sid->peerCert->derCert.len, 3); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendToItem(&plaintext, - ss->sec.ci.sid->peerCert->derCert.data, - ss->sec.ci.sid->peerCert->derCert.len); - if (rv != SECSuccess) - goto loser; - } else { - rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); - if (rv != SECSuccess) - goto loser; - } - - /* timestamp */ - now = ssl_Time(); - rv = ssl3_AppendNumberToItem(&plaintext, now, - sizeof(ticket.ticket_lifetime_hint)); - if (rv != SECSuccess) - goto loser; - - if (srvNameLen) { - /* Name Type (sni_host_name) */ - rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1); - if (rv != SECSuccess) - goto loser; - /* HostName (length and value) */ - rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len); - if (rv != SECSuccess) - goto loser; - } else { - /* No Name */ - rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME, 1); - if (rv != SECSuccess) - goto loser; - } - - /* extendedMasterSecretUsed */ - rv = ssl3_AppendNumberToItem( - &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1); - if (rv != SECSuccess) - goto loser; - - PORT_Assert(plaintext.len == padding_length); - for (i = 0; i < padding_length; i++) - plaintext.data[i] = (unsigned char)padding_length; - - if (SECITEM_AllocItem(NULL, &ciphertext, ciphertext_length) == NULL) { - rv = SECFailure; - goto loser; - } - -/* Generate encrypted portion of ticket. */ -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - aes_ctx = (AESContext *)aes_ctx_buf; - rv = AES_InitContext(aes_ctx, aes_key, aes_key_length, iv, - NSS_AES_CBC, 1, AES_BLOCK_SIZE); - if (rv != SECSuccess) - goto loser; - - rv = AES_Encrypt(aes_ctx, ciphertext.data, &ciphertext.len, - ciphertext.len, plaintext_item.data, - plaintext_item.len); - if (rv != SECSuccess) - goto loser; - } else -#endif - { - aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech, - CKA_ENCRYPT, aes_key_pkcs11, &ivItem); - if (!aes_ctx_pkcs11) - goto loser; - - rv = PK11_CipherOp(aes_ctx_pkcs11, ciphertext.data, - (int *)&ciphertext.len, ciphertext.len, - plaintext_item.data, plaintext_item.len); - PK11_Finalize(aes_ctx_pkcs11); - PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE); - if (rv != SECSuccess) - goto loser; - } - - /* Convert ciphertext length to network order. */ - length_buf[0] = (ciphertext.len >> 8) & 0xff; - length_buf[1] = (ciphertext.len) & 0xff; - -/* Compute MAC. */ -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - hmac_ctx = (HMACContext *)hmac_ctx_buf; - hashObj = HASH_GetRawHashObject(HASH_AlgSHA256); - if (HMAC_Init(hmac_ctx, hashObj, mac_key, - mac_key_length, PR_FALSE) != SECSuccess) - goto loser; - - HMAC_Begin(hmac_ctx); - HMAC_Update(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN); - HMAC_Update(hmac_ctx, iv, sizeof(iv)); - HMAC_Update(hmac_ctx, (unsigned char *)length_buf, 2); - HMAC_Update(hmac_ctx, ciphertext.data, ciphertext.len); - HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length, - sizeof(computed_mac)); - } else -#endif - { - SECItem macParam; - macParam.data = NULL; - macParam.len = 0; - hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech, - CKA_SIGN, mac_key_pkcs11, &macParam); - if (!hmac_ctx_pkcs11) - goto loser; - - rv = PK11_DigestBegin(hmac_ctx_pkcs11); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx_pkcs11, key_name, - SESS_TICKET_KEY_NAME_LEN); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx_pkcs11, iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx_pkcs11, (unsigned char *)length_buf, 2); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx_pkcs11, ciphertext.data, ciphertext.len); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac, - &computed_mac_length, sizeof(computed_mac)); - if (rv != SECSuccess) - goto loser; - } - - /* Serialize the handshake message. */ - rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, message_length); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_lifetime_hint, - sizeof(ticket.ticket_lifetime_hint)); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshakeNumber(ss, - message_length - sizeof(ticket.ticket_lifetime_hint) - 2, - 2); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshake(ss, key_name, SESS_TICKET_KEY_NAME_LEN); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshake(ss, iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshakeVariable(ss, ciphertext.data, ciphertext.len, 2); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshake(ss, computed_mac, computed_mac_length); - if (rv != SECSuccess) - goto loser; - -loser: - if (hmac_ctx_pkcs11) - PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); - if (plaintext_item.data) - SECITEM_FreeItem(&plaintext_item, PR_FALSE); - if (ciphertext.data) - SECITEM_FreeItem(&ciphertext, PR_FALSE); - - return rv; -} - -/* When a client receives a SessionTicket extension a NewSessionTicket - * message is expected during the handshake. - */ -SECStatus -ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - if (data->len != 0) { - return SECSuccess; /* Ignore the extension. */ - } - - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - return SECSuccess; -} - -SECStatus -ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - SECStatus rv; - SECItem *decrypted_state = NULL; - SessionTicket *parsed_session_ticket = NULL; - sslSessionID *sid = NULL; - SSL3Statistics *ssl3stats; - - /* Ignore the SessionTicket extension if processing is disabled. */ - if (!ss->opt.enableSessionTickets) { - return SECSuccess; - } - - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - - /* Parse the received ticket sent in by the client. We are - * lenient about some parse errors, falling back to a fullshake - * instead of terminating the current connection. - */ - if (data->len == 0) { - ss->xtnData.emptySessionTicket = PR_TRUE; - } else { - PRUint32 i; - SECItem extension_data; - EncryptedSessionTicket enc_session_ticket; - unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; - unsigned int computed_mac_length; -#ifndef NO_PKCS11_BYPASS - const SECHashObject *hashObj; - const unsigned char *aes_key; - const unsigned char *mac_key; - PRUint32 aes_key_length; - PRUint32 mac_key_length; - PRUint64 hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS]; - HMACContext *hmac_ctx; - PRUint64 aes_ctx_buf[MAX_CIPHER_CONTEXT_LLONGS]; - AESContext *aes_ctx; -#endif - PK11SymKey *aes_key_pkcs11; - PK11SymKey *mac_key_pkcs11; - PK11Context *hmac_ctx_pkcs11; - CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC; - PK11Context *aes_ctx_pkcs11; - CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC; - unsigned char *padding; - PRUint32 padding_length; - unsigned char *buffer; - unsigned int buffer_len; - PRInt32 temp; - SECItem cert_item; - PRInt8 nameType = TLS_STE_NO_SERVER_NAME; - - /* Turn off stateless session resumption if the client sends a - * SessionTicket extension, even if the extension turns out to be - * malformed (ss->sec.ci.sid is non-NULL when doing session - * renegotiation.) - */ - if (ss->sec.ci.sid != NULL) { - if (ss->sec.uncache) - ss->sec.uncache(ss->sec.ci.sid); - ssl_FreeSID(ss->sec.ci.sid); - ss->sec.ci.sid = NULL; - } - - extension_data.data = data->data; /* Keep a copy for future use. */ - extension_data.len = data->len; - - if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket) != - SECSuccess) { - return SECSuccess; /* Pretend it isn't there */ - } - -/* Get session ticket keys. */ -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length, - &mac_key, &mac_key_length); - } else -#endif - { - rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11, - &mac_key_pkcs11); - } - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.", - SSL_GETPID(), ss->fd)); - goto loser; - } - - /* If the ticket sent by the client was generated under a key different - * from the one we have, bypass ticket processing. - */ - if (PORT_Memcmp(enc_session_ticket.key_name, key_name, - SESS_TICKET_KEY_NAME_LEN) != 0) { - SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.", - SSL_GETPID(), ss->fd)); - goto no_ticket; - } - - /* Verify the MAC on the ticket. MAC verification may also - * fail if the MAC key has been recently refreshed. - */ -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - hmac_ctx = (HMACContext *)hmac_ctx_buf; - hashObj = HASH_GetRawHashObject(HASH_AlgSHA256); - if (HMAC_Init(hmac_ctx, hashObj, mac_key, - sizeof(session_ticket_mac_key), PR_FALSE) != SECSuccess) - goto no_ticket; - HMAC_Begin(hmac_ctx); - HMAC_Update(hmac_ctx, extension_data.data, - extension_data.len - TLS_EX_SESS_TICKET_MAC_LENGTH); - if (HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length, - sizeof(computed_mac)) != SECSuccess) - goto no_ticket; - } else -#endif - { - SECItem macParam; - macParam.data = NULL; - macParam.len = 0; - hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech, - CKA_SIGN, mac_key_pkcs11, &macParam); - if (!hmac_ctx_pkcs11) { - SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.", - SSL_GETPID(), ss->fd, PORT_GetError())); - goto no_ticket; - } else { - SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.", - SSL_GETPID(), ss->fd)); - } - rv = PK11_DigestBegin(hmac_ctx_pkcs11); - rv = PK11_DigestOp(hmac_ctx_pkcs11, extension_data.data, - extension_data.len - - TLS_EX_SESS_TICKET_MAC_LENGTH); - if (rv != SECSuccess) { - PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); - goto no_ticket; - } - rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac, - &computed_mac_length, sizeof(computed_mac)); - PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); - if (rv != SECSuccess) - goto no_ticket; - } - if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac, - computed_mac_length) != - 0) { - SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.", - SSL_GETPID(), ss->fd)); - goto no_ticket; - } - - /* We ignore key_name for now. - * This is ok as MAC verification succeeded. - */ - - /* Decrypt the ticket. */ - - /* Plaintext is shorter than the ciphertext due to padding. */ - decrypted_state = SECITEM_AllocItem(NULL, NULL, - enc_session_ticket.encrypted_state.len); - -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - aes_ctx = (AESContext *)aes_ctx_buf; - rv = AES_InitContext(aes_ctx, aes_key, - sizeof(session_ticket_enc_key), enc_session_ticket.iv, - NSS_AES_CBC, 0, AES_BLOCK_SIZE); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", - SSL_GETPID(), ss->fd)); - goto no_ticket; - } - - rv = AES_Decrypt(aes_ctx, decrypted_state->data, - &decrypted_state->len, decrypted_state->len, - enc_session_ticket.encrypted_state.data, - enc_session_ticket.encrypted_state.len); - if (rv != SECSuccess) - goto no_ticket; - } else -#endif - { - SECItem ivItem; - ivItem.data = enc_session_ticket.iv; - ivItem.len = AES_BLOCK_SIZE; - aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech, - CKA_DECRYPT, aes_key_pkcs11, &ivItem); - if (!aes_ctx_pkcs11) { - SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", - SSL_GETPID(), ss->fd)); - goto no_ticket; - } - - rv = PK11_CipherOp(aes_ctx_pkcs11, decrypted_state->data, - (int *)&decrypted_state->len, decrypted_state->len, - enc_session_ticket.encrypted_state.data, - enc_session_ticket.encrypted_state.len); - PK11_Finalize(aes_ctx_pkcs11); - PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE); - if (rv != SECSuccess) - goto no_ticket; - } - - /* Check padding. */ - padding_length = - (PRUint32)decrypted_state->data[decrypted_state->len - 1]; - if (padding_length == 0 || padding_length > AES_BLOCK_SIZE) - goto no_ticket; - - padding = &decrypted_state->data[decrypted_state->len - padding_length]; - for (i = 0; i < padding_length; i++, padding++) { - if (padding_length != (PRUint32)*padding) - goto no_ticket; - } - - /* Deserialize session state. */ - buffer = decrypted_state->data; - buffer_len = decrypted_state->len; - - parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket)); - if (parsed_session_ticket == NULL) { - rv = SECFailure; - goto loser; - } - - /* Read ticket_version and reject if the version is wrong */ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp != TLS_EX_SESS_TICKET_VERSION) - goto no_ticket; - - parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp; - - /* Read SSLVersion. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp; - - /* Read cipher_suite. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp; - - /* Read compression_method. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->compression_method = (SSLCompressionMethod)temp; - - /* Read cipher spec parameters. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->authAlgorithm = (SSLSignType)temp; - temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->authKeyBits = (PRUint32)temp; - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->keaType = (SSLKEAType)temp; - temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->keaKeyBits = (PRUint32)temp; - - /* Read wrapped master_secret. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->ms_is_wrapped = (PRBool)temp; - - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->exchKeyType = (SSL3KEAType)temp; - - temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp; - - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->ms_length = (PRUint16)temp; - if (parsed_session_ticket->ms_length == 0 || /* sanity check MS. */ - parsed_session_ticket->ms_length > - sizeof(parsed_session_ticket->master_secret)) - goto no_ticket; - - /* Allow for the wrapped master secret to be longer. */ - if (buffer_len < parsed_session_ticket->ms_length) - goto no_ticket; - PORT_Memcpy(parsed_session_ticket->master_secret, buffer, - parsed_session_ticket->ms_length); - buffer += parsed_session_ticket->ms_length; - buffer_len -= parsed_session_ticket->ms_length; - - /* Read client_identity */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->client_identity.client_auth_type = - (ClientAuthenticationType)temp; - switch (parsed_session_ticket->client_identity.client_auth_type) { - case CLIENT_AUTH_ANONYMOUS: - break; - case CLIENT_AUTH_CERTIFICATE: - rv = ssl3_ConsumeHandshakeVariable(ss, &cert_item, 3, - &buffer, &buffer_len); - if (rv != SECSuccess) - goto no_ticket; - rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert, - &cert_item); - if (rv != SECSuccess) - goto no_ticket; - break; - default: - goto no_ticket; - } - /* Read timestamp. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->timestamp = (PRUint32)temp; - - /* Read server name */ - nameType = - ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (nameType != TLS_STE_NO_SERVER_NAME) { - SECItem name_item; - rv = ssl3_ConsumeHandshakeVariable(ss, &name_item, 2, &buffer, - &buffer_len); - if (rv != SECSuccess) - goto no_ticket; - rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName, - &name_item); - if (rv != SECSuccess) - goto no_ticket; - parsed_session_ticket->srvName.type = nameType; - } - - /* Read extendedMasterSecretUsed */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); - parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp; - - /* Done parsing. Check that all bytes have been consumed. */ - if (buffer_len != padding_length) - goto no_ticket; - - /* Use the ticket if it has not expired, otherwise free the allocated - * memory since the ticket is of no use. - */ - if (parsed_session_ticket->timestamp != 0 && - parsed_session_ticket->timestamp + - TLS_EX_SESS_TICKET_LIFETIME_HINT > - ssl_Time()) { - - sid = ssl3_NewSessionID(ss, PR_TRUE); - if (sid == NULL) { - rv = SECFailure; - goto loser; - } - - /* Copy over parameters. */ - sid->version = parsed_session_ticket->ssl_version; - sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite; - sid->u.ssl3.compression = parsed_session_ticket->compression_method; - sid->authAlgorithm = parsed_session_ticket->authAlgorithm; - sid->authKeyBits = parsed_session_ticket->authKeyBits; - sid->keaType = parsed_session_ticket->keaType; - sid->keaKeyBits = parsed_session_ticket->keaKeyBits; - -/* Copy master secret. */ -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11 && - parsed_session_ticket->ms_is_wrapped) - goto no_ticket; -#endif - if (parsed_session_ticket->ms_length > - sizeof(sid->u.ssl3.keys.wrapped_master_secret)) - goto no_ticket; - PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, - parsed_session_ticket->master_secret, - parsed_session_ticket->ms_length); - sid->u.ssl3.keys.wrapped_master_secret_len = - parsed_session_ticket->ms_length; - sid->u.ssl3.exchKeyType = parsed_session_ticket->exchKeyType; - sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech; - sid->u.ssl3.keys.msIsWrapped = - parsed_session_ticket->ms_is_wrapped; - sid->u.ssl3.masterValid = PR_TRUE; - sid->u.ssl3.keys.resumable = PR_TRUE; - sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket->extendedMasterSecretUsed; - - /* Copy over client cert from session ticket if there is one. */ - if (parsed_session_ticket->peer_cert.data != NULL) { - if (sid->peerCert != NULL) - CERT_DestroyCertificate(sid->peerCert); - sid->peerCert = CERT_NewTempCertificate(ss->dbHandle, - &parsed_session_ticket->peer_cert, NULL, PR_FALSE, PR_TRUE); - if (sid->peerCert == NULL) { - rv = SECFailure; - goto loser; - } - } - if (parsed_session_ticket->srvName.data != NULL) { - sid->u.ssl3.srvName = parsed_session_ticket->srvName; - } - ss->statelessResume = PR_TRUE; - ss->sec.ci.sid = sid; - } - } - - if (0) { - no_ticket: - SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.", - SSL_GETPID(), ss->fd)); - ssl3stats = SSL_GetStatistics(); - SSL_AtomicIncrementLong(&ssl3stats->hch_sid_ticket_parse_failures); - } - rv = SECSuccess; - -loser: - /* ss->sec.ci.sid == sid if it did NOT come here via goto statement - * in that case do not free sid - */ - if (sid && (ss->sec.ci.sid != sid)) { - ssl_FreeSID(sid); - sid = NULL; - } - if (decrypted_state != NULL) { - SECITEM_FreeItem(decrypted_state, PR_TRUE); - decrypted_state = NULL; - } - - if (parsed_session_ticket != NULL) { - if (parsed_session_ticket->peer_cert.data) { - SECITEM_FreeItem(&parsed_session_ticket->peer_cert, PR_FALSE); - } - PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket)); - } - - return rv; -} - -/* - * Read bytes. Using this function means the SECItem structure - * cannot be freed. The caller is expected to call this function - * on a shallow copy of the structure. - */ -static SECStatus -ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes) -{ - if (bytes > item->len) - return SECFailure; - - *buf = item->data; - item->data += bytes; - item->len -= bytes; - return SECSuccess; -} - -static SECStatus -ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, - EncryptedSessionTicket *enc_session_ticket) -{ - if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name, - SESS_TICKET_KEY_NAME_LEN) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv, - AES_BLOCK_SIZE) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeHandshakeVariable(ss, &enc_session_ticket->encrypted_state, - 2, &data->data, &data->len) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeFromItem(data, &enc_session_ticket->mac, - TLS_EX_SESS_TICKET_MAC_LENGTH) != - SECSuccess) - return SECFailure; - if (data->len != 0) /* Make sure that we have consumed all bytes. */ - return SECFailure; - - return SECSuccess; -} - -/* go through hello extensions in buffer "b". - * For each one, find the extension handler in the table, and - * if present, invoke that handler. - * Servers ignore any extensions with unknown extension types. - * Clients reject any extensions with unadvertised extension types. - * In TLS >= 1.3, the client checks that extensions appear in the - * right phase. - */ -SECStatus -ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length, - SSL3HandshakeType handshakeMessage) -{ - const ssl3HelloExtensionHandler *handlers; - PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; - - switch (handshakeMessage) { - case client_hello: - handlers = clientHelloHandlers; - break; - case encrypted_extensions: - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - /* fall through */ - case server_hello: - if (ss->version > SSL_LIBRARY_VERSION_3_0) { - handlers = serverHelloHandlersTLS; - } else { - handlers = serverHelloHandlersSSL3; - } - break; - default: - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - PORT_Assert(0); - return SECFailure; - } - - while (*length) { - const ssl3HelloExtensionHandler *handler; - SECStatus rv; - PRInt32 extension_type; - SECItem extension_data; - - /* Get the extension's type field */ - extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (extension_type < 0) /* failure to decode extension_type */ - return SECFailure; /* alert already sent */ - - /* get the data for this extension, so we can pass it or skip it. */ - rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length); - if (rv != SECSuccess) - return rv; /* alert already sent */ - - /* Check whether the server sent an extension which was not advertised - * in the ClientHello */ - if (!ss->sec.isServer && - !ssl3_ClientExtensionAdvertised(ss, extension_type)) { - (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension); - return SECFailure; - } - - /* Check whether an extension has been sent multiple times. */ - if (ssl3_ExtensionNegotiated(ss, extension_type)) { - (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - return SECFailure; - } - - /* Check that this is a legal extension in TLS 1.3 */ - if (isTLS13 && !tls13_ExtensionAllowed(extension_type, handshakeMessage)) { - if (handshakeMessage == client_hello) { - /* Skip extensions not used in TLS 1.3 */ - continue; - } - tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, - unsupported_extension); - return SECFailure; - } - - /* find extension_type in table of Hello Extension Handlers */ - for (handler = handlers; handler->ex_type >= 0; handler++) { - /* if found, call this handler */ - if (handler->ex_type == extension_type) { - rv = (*handler->ex_handler)(ss, (PRUint16)extension_type, - &extension_data); - if (rv != SECSuccess) { - if (!ss->ssl3.fatalAlertSent) { - /* send a generic alert if the handler didn't already */ - (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); - } - return SECFailure; - } - } - } - } - return SECSuccess; -} - -/* Add a callback function to the table of senders of server hello extensions. - */ -SECStatus -ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, - ssl3HelloExtensionSenderFunc cb) -{ - int i; - ssl3HelloExtensionSender *sender; - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - sender = &ss->xtnData.serverHelloSenders[0]; - } else { - if (tls13_ExtensionAllowed(ex_type, server_hello)) { - PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions)); - sender = &ss->xtnData.serverHelloSenders[0]; - } else { - PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions)); - sender = &ss->xtnData.encryptedExtensionsSenders[0]; - } - } - - for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { - if (!sender->ex_sender) { - sender->ex_type = ex_type; - sender->ex_sender = cb; - return SECSuccess; - } - /* detect duplicate senders */ - PORT_Assert(sender->ex_type != ex_type); - if (sender->ex_type == ex_type) { - /* duplicate */ - break; - } - } - PORT_Assert(i < SSL_MAX_EXTENSIONS); /* table needs to grow */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; -} - -/* call each of the extension senders and return the accumulated length */ -PRInt32 -ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, - const ssl3HelloExtensionSender *sender) -{ - PRInt32 total_exten_len = 0; - int i; - - if (!sender) { - if (ss->version > SSL_LIBRARY_VERSION_3_0) { - sender = &clientHelloSendersTLS[0]; - } else { - sender = &clientHelloSendersSSL3[0]; - } - } - - for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { - if (sender->ex_sender) { - PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes); - if (extLen < 0) - return -1; - maxBytes -= extLen; - total_exten_len += extLen; - } - } - return total_exten_len; -} - -/* Extension format: - * Extension number: 2 bytes - * Extension length: 2 bytes - * Verify Data Length: 1 byte - * Verify Data (TLS): 12 bytes (client) or 24 bytes (server) - * Verify Data (SSL): 36 bytes (client) or 72 bytes (server) - */ -static PRInt32 -ssl3_SendRenegotiationInfoXtn( - sslSocket *ss, - PRBool append, - PRUint32 maxBytes) -{ - PRInt32 len = 0; - PRInt32 needed; - - /* In draft-ietf-tls-renegotiation-03, it is NOT RECOMMENDED to send - * both the SCSV and the empty RI, so when we send SCSV in - * the initial handshake, we don't also send RI. - */ - if (!ss || ss->ssl3.hs.sendingSCSV) - return 0; - if (ss->firstHsDone) { - len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 - : ss->ssl3.hs.finishedBytes; - } - needed = 5 + len; - if (maxBytes < (PRUint32)needed) { - return 0; - } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_AppendHandshakeNumber(ss, len + 1, 2); - if (rv != SECSuccess) - return -1; - /* verify_Data from previous Finished message(s) */ - rv = ssl3_AppendHandshakeVariable(ss, - ss->ssl3.hs.finishedMsgs.data, len, 1); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_renegotiation_info_xtn; - } - } - return needed; -} - -static SECStatus -ssl3_ServerHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - SECStatus rv = SECSuccess; - - /* remember that we got this extension. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - PORT_Assert(ss->sec.isServer); - /* prepare to send back the appropriate response */ - rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, - ssl3_ServerSendStatusRequestXtn); - return rv; -} - -/* This function runs in both the client and server. */ -static SECStatus -ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv = SECSuccess; - PRUint32 len = 0; - - if (ss->firstHsDone) { - len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes - : ss->ssl3.hs.finishedBytes * 2; - } - if (data->len != 1 + len || data->data[0] != len) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - if (len && NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data, - data->data + 1, len)) { - (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); - PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); - return SECFailure; - } - /* remember that we got this extension and it was correct. */ - ss->peerRequestedProtection = 1; - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - if (ss->sec.isServer) { - /* prepare to send back the appropriate response */ - rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, - ssl3_SendRenegotiationInfoXtn); - } - return rv; -} - -static PRInt32 -ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) -{ - PRUint32 ext_data_len; - PRInt16 i; - SECStatus rv; - - if (!ss) - return 0; - - if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) - return 0; /* Not relevant */ - - ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1; - - if (append && maxBytes >= 4 + ext_data_len) { - /* Extension type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2); - if (rv != SECSuccess) - return -1; - /* Length of extension data */ - rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2); - if (rv != SECSuccess) - return -1; - /* Length of the SRTP cipher list */ - rv = ssl3_AppendHandshakeNumber(ss, - 2 * ss->ssl3.dtlsSRTPCipherCount, - 2); - if (rv != SECSuccess) - return -1; - /* The SRTP ciphers */ - for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) { - rv = ssl3_AppendHandshakeNumber(ss, - ss->ssl3.dtlsSRTPCiphers[i], - 2); - } - /* Empty MKI value */ - ssl3_AppendHandshakeVariable(ss, NULL, 0, 1); - - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_use_srtp_xtn; - } - - return 4 + ext_data_len; -} - -static PRInt32 -ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) -{ - SECStatus rv; - - /* Server side */ - if (!append || maxBytes < 9) { - return 9; - } - - /* Extension type */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2); - if (rv != SECSuccess) - return -1; - /* Length of extension data */ - rv = ssl3_AppendHandshakeNumber(ss, 5, 2); - if (rv != SECSuccess) - return -1; - /* Length of the SRTP cipher list */ - rv = ssl3_AppendHandshakeNumber(ss, 2, 2); - if (rv != SECSuccess) - return -1; - /* The selected cipher */ - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2); - if (rv != SECSuccess) - return -1; - /* Empty MKI value */ - ssl3_AppendHandshakeVariable(ss, NULL, 0, 1); - - return 9; -} - -static SECStatus -ssl3_ClientHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - SECItem ciphers = { siBuffer, NULL, 0 }; - PRUint16 i; - PRUint16 cipher = 0; - PRBool found = PR_FALSE; - SECItem litem; - - if (!data->data || !data->len) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* Get the cipher list */ - rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2, - &data->data, &data->len); - if (rv != SECSuccess) { - return SECFailure; /* fatal alert already sent */ - } - /* Now check that the server has picked just 1 (i.e., len = 2) */ - if (ciphers.len != 2) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* Get the selected cipher */ - cipher = (ciphers.data[0] << 8) | ciphers.data[1]; - - /* Now check that this is one of the ciphers we offered */ - for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) { - if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) { - found = PR_TRUE; - break; - } - } - - if (!found) { - (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); - return SECFailure; - } - - /* Get the srtp_mki value */ - rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1, - &data->data, &data->len); - if (rv != SECSuccess) { - return SECFailure; /* alert already sent */ - } - - /* We didn't offer an MKI, so this must be 0 length */ - if (litem.len != 0) { - (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); - return SECFailure; - } - - /* extra trailing bytes */ - if (data->len != 0) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* OK, this looks fine. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn; - ss->ssl3.dtlsSRTPCipherSuite = cipher; - return SECSuccess; -} - -static SECStatus -ssl3_ServerHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - SECItem ciphers = { siBuffer, NULL, 0 }; - PRUint16 i; - unsigned int j; - PRUint16 cipher = 0; - PRBool found = PR_FALSE; - SECItem litem; - - if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) { - /* Ignore the extension if we aren't doing DTLS or no DTLS-SRTP - * preferences have been set. */ - return SECSuccess; - } - - if (!data->data || data->len < 5) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* Get the cipher list */ - rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2, - &data->data, &data->len); - if (rv != SECSuccess) { - return SECFailure; /* alert already sent */ - } - /* Check that the list is even length */ - if (ciphers.len % 2) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* Walk through the offered list and pick the most preferred of our - * ciphers, if any */ - for (i = 0; !found && i < ss->ssl3.dtlsSRTPCipherCount; i++) { - for (j = 0; j + 1 < ciphers.len; j += 2) { - cipher = (ciphers.data[j] << 8) | ciphers.data[j + 1]; - if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) { - found = PR_TRUE; - break; - } - } - } - - /* Get the srtp_mki value */ - rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1, &data->data, &data->len); - if (rv != SECSuccess) { - return SECFailure; - } - - if (data->len != 0) { - (void)ssl3_DecodeError(ss); /* trailing bytes */ - return SECFailure; - } - - /* Now figure out what to do */ - if (!found) { - /* No matching ciphers, pretend we don't support use_srtp */ - return SECSuccess; - } - - /* OK, we have a valid cipher and we've selected it */ - ss->ssl3.dtlsSRTPCipherSuite = cipher; - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn; - - return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn, - ssl3_ServerSendUseSRTPXtn); -} - -/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension - * from a client. - * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -static SECStatus -ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - SECItem algorithms; - const unsigned char *b; - unsigned int numAlgorithms, i; - - /* Ignore this extension if we aren't doing TLS 1.2 or greater. */ - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { - return SECSuccess; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data, - &data->len); - if (rv != SECSuccess) { - return SECFailure; - } - /* Trailing data, empty value, or odd-length value is invalid. */ - if (data->len != 0 || algorithms.len == 0 || (algorithms.len & 1) != 0) { - (void)SSL3_SendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - return SECFailure; - } - - numAlgorithms = algorithms.len / 2; - - /* We don't care to process excessive numbers of algorithms. */ - if (numAlgorithms > 512) { - numAlgorithms = 512; - } - - ss->ssl3.hs.clientSigAndHash = - PORT_NewArray(SSLSignatureAndHashAlg, numAlgorithms); - if (!ss->ssl3.hs.clientSigAndHash) { - (void)SSL3_SendAlert(ss, alert_fatal, internal_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - return SECFailure; - } - ss->ssl3.hs.numClientSigAndHash = 0; - - b = algorithms.data; - ss->ssl3.hs.numClientSigAndHash = 0; - for (i = 0; i < numAlgorithms; i++) { - SSLSignatureAndHashAlg *sigAndHash = - &ss->ssl3.hs.clientSigAndHash[ss->ssl3.hs.numClientSigAndHash]; - sigAndHash->hashAlg = (SSLHashType) * (b++); - sigAndHash->sigAlg = (SSLSignType) * (b++); - if (ssl3_IsSupportedSignatureAlgorithm(sigAndHash)) { - ++ss->ssl3.hs.numClientSigAndHash; - } - } - - if (!ss->ssl3.hs.numClientSigAndHash) { - /* We didn't understand any of the client's requested signature - * formats. We'll use the defaults. */ - PORT_Free(ss->ssl3.hs.clientSigAndHash); - ss->ssl3.hs.clientSigAndHash = NULL; - } - - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - return SECSuccess; -} - -/* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS - * 1.2 ClientHellos. */ -static PRInt32 -ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) -{ - PRInt32 extension_length; - unsigned int i; - PRInt32 pos = 0; - PRUint32 policy; - PRUint8 buf[MAX_SIGNATURE_ALGORITHMS * 2]; - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { - return 0; - } - - for (i = 0; i < ss->ssl3.signatureAlgorithmCount; i++) { - SECOidTag hashOID = ssl3_TLSHashAlgorithmToOID( - ss->ssl3.signatureAlgorithms[i].hashAlg); - if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) || - (policy & NSS_USE_ALG_IN_SSL_KX)) { - buf[pos++] = ss->ssl3.signatureAlgorithms[i].hashAlg; - buf[pos++] = ss->ssl3.signatureAlgorithms[i].sigAlg; - } - } - - extension_length = - 2 /* extension type */ + - 2 /* extension length */ + - 2 /* supported_signature_algorithms length */ + - pos; - - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) { - return -1; - } - - rv = ssl3_AppendHandshakeVariable(ss, buf, extension_length - 6, 2); - if (rv != SECSuccess) { - return -1; - } - - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_signature_algorithms_xtn; - } - - return extension_length; -} - -unsigned int -ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength) -{ - unsigned int recordLength = 1 /* handshake message type */ + - 3 /* handshake message length */ + - clientHelloLength; - unsigned int extensionLength; - - if (recordLength < 256 || recordLength >= 512) { - return 0; - } - - extensionLength = 512 - recordLength; - /* Extensions take at least four bytes to encode. Always include at least - * one byte of data if including the extension. WebSphere Application - * Server 7.0 is intolerant to the last extension being zero-length. */ - if (extensionLength < 4 + 1) { - extensionLength = 4 + 1; - } - - return extensionLength; -} - -/* ssl3_AppendPaddingExtension possibly adds an extension which ensures that a - * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures - * that we don't trigger bugs in F5 products. */ -PRInt32 -ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, - PRUint32 maxBytes) -{ - unsigned int paddingLen = extensionLen - 4; - static unsigned char padding[256]; - - if (extensionLen == 0) { - return 0; - } - - if (extensionLen < 4 || - extensionLen > maxBytes || - paddingLen > sizeof(padding)) { - PORT_Assert(0); - return -1; - } - - if (SECSuccess != ssl3_AppendHandshakeNumber(ss, ssl_padding_xtn, 2)) - return -1; - if (SECSuccess != ssl3_AppendHandshakeNumber(ss, paddingLen, 2)) - return -1; - if (SECSuccess != ssl3_AppendHandshake(ss, padding, paddingLen)) - return -1; - - return extensionLen; -} - -/* ssl3_ClientSendDraftVersionXtn sends the TLS 1.3 temporary draft - * version extension. - * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */ -static PRInt32 -ssl3_ClientSendDraftVersionXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) -{ - PRInt32 extension_length; - - if (ss->version != SSL_LIBRARY_VERSION_TLS_1_3) { - return 0; - } - - extension_length = 6; /* Type + length + number */ - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_draft_version_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, TLS_1_3_DRAFT_VERSION, 2); - if (rv != SECSuccess) - goto loser; - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_tls13_draft_version_xtn; - } - - return extension_length; - -loser: - return -1; -} - -/* ssl3_ServerHandleDraftVersionXtn handles the TLS 1.3 temporary draft - * version extension. - * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */ -static SECStatus -ssl3_ServerHandleDraftVersionXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - PRInt32 draft_version; - - /* Ignore this extension if we aren't doing TLS 1.3 */ - if (ss->version != SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; - } - - if (data->len != 2) { - (void)ssl3_DecodeError(ss); - return SECFailure; - } - - /* Get the draft version out of the handshake */ - draft_version = ssl3_ConsumeHandshakeNumber(ss, 2, - &data->data, &data->len); - if (draft_version < 0) { - return SECFailure; - } - - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - - if (draft_version != TLS_1_3_DRAFT_VERSION) { - /* - * Incompatible/broken TLS 1.3 implementation. Fall back to TLS 1.2. - * TODO(ekr@rtfm.com): It's not entirely clear it's safe to roll back - * here. Need to double-check. - */ - SSL_TRC(30, ("%d: SSL3[%d]: Incompatible version of TLS 1.3 (%d), " - "expected %d", - SSL_GETPID(), ss->fd, draft_version, TLS_1_3_DRAFT_VERSION)); - ss->version = SSL_LIBRARY_VERSION_TLS_1_2; - } - - return SECSuccess; -} - -static PRInt32 -ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length; - - if (!ss->opt.enableExtendedMS) { - return 0; - } - -#ifndef NO_PKCS11_BYPASS - /* Extended MS can only be used w/o bypass mode */ - if (ss->opt.bypassPKCS11) { - PORT_Assert(0); - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return -1; - } -#endif - - /* Always send the extension in this function, since the - * client always sends it and this function is only called on - * the server if we negotiated the extension. */ - extension_length = 4; /* Type + length (0) */ - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_AppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_extended_master_secret_xtn; - } - - return extension_length; - -loser: - return -1; -} - -static SECStatus -ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) { - return SECSuccess; - } - - if (!ss->opt.enableExtendedMS) { - return SECSuccess; - } - -#ifndef NO_PKCS11_BYPASS - /* Extended MS can only be used w/o bypass mode */ - if (ss->opt.bypassPKCS11) { - PORT_Assert(0); - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return SECFailure; - } -#endif - - if (data->len != 0) { - SSL_TRC(30, ("%d: SSL3[%d]: Bogus extended master secret extension", - SSL_GETPID(), ss->fd)); - return SECFailure; - } - - SSL_DBG(("%d: SSL[%d]: Negotiated extended master secret extension.", - SSL_GETPID(), ss->fd)); - - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - - if (ss->sec.isServer) { - return ssl3_RegisterServerHelloExtensionSender( - ss, ex_type, ssl3_SendExtendedMasterSecretXtn); - } - return SECSuccess; -} - -/* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp - * extension for TLS ClientHellos. */ -static PRInt32 -ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length = 2 /* extension_type */ + - 2 /* length(extension_data) */; - - /* Only send the extension if processing is enabled. */ - if (!ss->opt.enableSignedCertTimestamps) - return 0; - - if (append && maxBytes >= extension_length) { - SECStatus rv; - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, - ssl_signed_cert_timestamp_xtn, - 2); - if (rv != SECSuccess) - goto loser; - /* zero length */ - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_signed_cert_timestamp_xtn; - } else if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - return extension_length; -loser: - return -1; -} - -static SECStatus -ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - /* We do not yet know whether we'll be resuming a session or creating - * a new one, so we keep a pointer to the data in the TLSExtensionData - * structure. This pointer is only valid in the scope of - * ssl3_HandleServerHello, and, if not resuming a session, the data is - * copied once a new session structure has been set up. - * All parsing is currently left to the application and we accept - * everything, including empty data. - */ - SECItem *scts = &ss->xtnData.signedCertTimestamps; - PORT_Assert(!scts->data && !scts->len); - - if (!data->len) { - /* Empty extension data: RFC 6962 mandates non-empty contents. */ - return SECFailure; - } - *scts = *data; - /* Keep track of negotiated extensions. */ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - return SECSuccess; -} - -static PRInt32 -ssl3_ServerSendSignedCertTimestampXtn(sslSocket *ss, - PRBool append, - PRUint32 maxBytes) -{ - PRInt32 extension_length; - SSLKEAType effectiveExchKeyType; - const SECItem *scts; - - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa || - ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) { - effectiveExchKeyType = ssl_kea_rsa; - } else { - effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; - } - - scts = &ss->signedCertTimestamps[effectiveExchKeyType]; - - if (!scts->len) { - /* No timestamps to send */ - return 0; - } - - extension_length = 2 /* extension_type */ + - 2 /* length(extension_data) */ + - scts->len; - - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, - ssl_signed_cert_timestamp_xtn, - 2); - if (rv != SECSuccess) - goto loser; - /* extension_data */ - rv = ssl3_AppendHandshakeVariable(ss, scts->data, scts->len, 2); - if (rv != SECSuccess) - goto loser; - } - - return extension_length; - -loser: - return -1; -} - -static SECStatus -ssl3_ServerHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type, - SECItem *data) -{ - ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; - PORT_Assert(ss->sec.isServer); - return ssl3_RegisterServerHelloExtensionSender(ss, ex_type, - ssl3_ServerSendSignedCertTimestampXtn); -} - -/* - * [draft-ietf-tls-tls13-11] Section 6.3.2.3. - * - * struct { - * NamedGroup group; - * opaque key_exchange<1..2^16-1>; - * } KeyShareEntry; - * - * struct { - * select (role) { - * case client: - * KeyShareEntry client_shares<4..2^16-1>; - * - * case server: - * KeyShareEntry server_share; - * } - * } KeyShare; - */ -static SECStatus -tls13_SizeOfKeyShareEntry(ssl3KeyPair *pair) -{ - return 2 + 2 + tls13_SizeOfECDHEKeyShareKEX(pair); -} - -static SECStatus -tls13_EncodeKeyShareEntry(sslSocket *ss, ssl3KeyPair *pair) -{ - SECStatus rv; - - /* This currently only works for ECC keys */ - PORT_Assert(pair->pubKey->keyType == ecKey); - if (pair->pubKey->keyType != ecKey) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - rv = ssl3_AppendHandshakeNumber(ss, tls13_GroupForECDHEKeyShare(pair), 2); - if (rv != SECSuccess) - return rv; - - rv = ssl3_AppendHandshakeNumber(ss, tls13_SizeOfECDHEKeyShareKEX(pair), 2); - if (rv != SECSuccess) - return rv; - - rv = tls13_EncodeECDHEKeyShareKEX(ss, pair); - if (rv != SECSuccess) - return rv; - - return SECSuccess; -} - -static PRInt32 -tls13_ClientSendKeyShareXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - SECStatus rv; - PRUint32 entry_length; - PRUint32 extension_length; - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return 0; - } - - /* Optimistically try to send an ECDHE key using the - * preexisting key (in future will be keys) */ - SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", - SSL_GETPID(), ss->fd)); - - entry_length = tls13_SizeOfKeyShareEntry(ss->ephemeralECDHKeyPair); - /* Type + length + vector_length + entry */ - extension_length = 2 + 2 + 2 + entry_length; - - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, entry_length + 2, 2); /* Extension length */ - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2); /* Vector length */ - if (rv != SECSuccess) - goto loser; - rv = tls13_EncodeKeyShareEntry(ss, ss->ephemeralECDHKeyPair); - if (rv != SECSuccess) - goto loser; - - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - ssl_tls13_key_share_xtn; - } - - return extension_length; - -loser: - return -1; -} - -static SECStatus -tls13_HandleKeyShareEntry(sslSocket *ss, SECItem *data) -{ - SECStatus rv; - PRInt32 group; - TLS13KeyShareEntry *ks = NULL; - SECItem share = { siBuffer, NULL, 0 }; - - group = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (group < 0) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); - goto loser; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &share, 2, &data->data, - &data->len); - if (rv != SECSuccess) - goto loser; - - ks = PORT_ZNew(TLS13KeyShareEntry); - if (!ks) - goto loser; - ks->group = group; - - rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share); - if (rv != SECSuccess) - goto loser; - - PR_APPEND_LINK(&ks->link, &ss->ssl3.hs.remoteKeyShares); - return SECSuccess; - -loser: - if (ks) - tls13_DestroyKeyShareEntry(ks); - return SECFailure; -} - -/* Handle an incoming KeyShare extension at the client and copy to - * |ss->ssl3.hs.remoteKeyShares| for future use. The key - * share is processed in tls13_HandleServerKeyShare(). */ -static SECStatus -tls13_ClientHandleKeyShareXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - - PORT_Assert(!ss->sec.isServer); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - /* This can't happen because the extension processing - * code filters out TLS 1.3 extensions when not in - * TLS 1.3 mode. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", - SSL_GETPID(), ss->fd)); - - rv = tls13_HandleKeyShareEntry(ss, data); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); - return SECFailure; - } - - if (data->len) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); - return SECFailure; - } - - return SECSuccess; -} - -/* Handle an incoming KeyShare extension at the server and copy to - * |ss->ssl3.hs.remoteKeyShares| for future use. The key - * share is processed in tls13_HandleClientKeyShare(). */ -static SECStatus -tls13_ServerHandleKeyShareXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) -{ - SECStatus rv; - PRInt32 length; - - PORT_Assert(ss->sec.isServer); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; - } - - SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", - SSL_GETPID(), ss->fd)); - - /* Redundant length because of TLS encoding (this vector consumes - * the entire extension.) */ - length = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, - &data->len); - if (length < 0) - goto loser; - if (length != data->len) { - /* Check for consistency */ - PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); - goto loser; - } - - while (data->len) { - rv = tls13_HandleKeyShareEntry(ss, data); - if (rv != SECSuccess) - goto loser; - } - return SECSuccess; - -loser: - tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares); - return SECFailure; -} - -PRInt32 -tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes) -{ - PRUint32 extension_length; - PRUint32 entry_length; - SECStatus rv; - - switch (ss->ssl3.hs.kea_def->exchKeyType) { -#ifndef NSS_DISABLE_ECC - case ssl_kea_ecdh: - PORT_Assert(ss->ephemeralECDHKeyPair); - break; -#endif - default: - /* got an unknown or unsupported Key Exchange Algorithm. - * Can't happen because tls13_HandleClientKeyShare - * enforces that we are ssl_kea_ecdh. */ - PORT_Assert(0); - tls13_FatalError(ss, SEC_ERROR_UNSUPPORTED_KEYALG, internal_error); - return SECFailure; - } - - entry_length = tls13_SizeOfKeyShareEntry(ss->ephemeralECDHKeyPair); - extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */ - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2); - if (rv != SECSuccess) - goto loser; - - rv = tls13_EncodeKeyShareEntry(ss, ss->ephemeralECDHKeyPair); - if (rv != SECSuccess) - goto loser; - } - - return extension_length; - -loser: - return -1; -}
diff --git a/net/third_party/nss/ssl/ssl3gthr.c b/net/third_party/nss/ssl/ssl3gthr.c deleted file mode 100644 index ea27713..0000000 --- a/net/third_party/nss/ssl/ssl3gthr.c +++ /dev/null
@@ -1,458 +0,0 @@ -/* - * Gather (Read) entire SSL3 records from socket into buffer. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" -#include "ssl3prot.h" - -/* - * Attempt to read in an entire SSL3 record. - * Blocks here for blocking sockets, otherwise returns -1 with - * PR_WOULD_BLOCK_ERROR when socket would block. - * - * returns 1 if received a complete SSL3 record. - * returns 0 if recv returns EOF - * returns -1 if recv returns < 0 - * (The error value may have already been set to PR_WOULD_BLOCK_ERROR) - * - * Caller must hold the recv buf lock. - * - * The Gather state machine has 3 states: GS_INIT, GS_HEADER, GS_DATA. - * GS_HEADER: waiting for the 5-byte SSL3 record header to come in. - * GS_DATA: waiting for the body of the SSL3 record to come in. - * - * This loop returns when either - * (a) an error or EOF occurs, - * (b) PR_WOULD_BLOCK_ERROR, - * (c) data (entire SSL3 record) has been received. - */ -static int -ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags) -{ - unsigned char *bp; - unsigned char *lbp; - int nb; - int err; - int rv = 1; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - if (gs->state == GS_INIT) { - gs->state = GS_HEADER; - gs->remainder = 5; - gs->offset = 0; - gs->writeOffset = 0; - gs->readOffset = 0; - gs->inbuf.len = 0; - } - - lbp = gs->inbuf.buf; - for (;;) { - SSL_TRC(30, ("%d: SSL3[%d]: gather state %d (need %d more)", - SSL_GETPID(), ss->fd, gs->state, gs->remainder)); - bp = ((gs->state != GS_HEADER) ? lbp : gs->hdr) + gs->offset; - nb = ssl_DefRecv(ss, bp, gs->remainder, flags); - - if (nb > 0) { - PRINT_BUF(60, (ss, "raw gather data:", bp, nb)); - } else if (nb == 0) { - /* EOF */ - SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd)); - rv = 0; - break; - } else /* if (nb < 0) */ { - SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd, - PR_GetError())); - rv = SECFailure; - break; - } - - PORT_Assert((unsigned int)nb <= gs->remainder); - if ((unsigned int)nb > gs->remainder) { - /* ssl_DefRecv is misbehaving! this error is fatal to SSL. */ - gs->state = GS_INIT; /* so we don't crash next time */ - rv = SECFailure; - break; - } - - gs->offset += nb; - gs->remainder -= nb; - if (gs->state == GS_DATA) - gs->inbuf.len += nb; - - /* if there's more to go, read some more. */ - if (gs->remainder > 0) { - continue; - } - - /* have received entire record header, or entire record. */ - switch (gs->state) { - case GS_HEADER: - /* - ** Have received SSL3 record header in gs->hdr. - ** Now extract the length of the following encrypted data, - ** and then read in the rest of the SSL3 record into gs->inbuf. - */ - gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; - - /* This is the max fragment length for an encrypted fragment - ** plus the size of the record header. - */ - if (gs->remainder > (MAX_FRAGMENT_LENGTH + 2048 + 5)) { - SSL3_SendAlert(ss, alert_fatal, unexpected_message); - gs->state = GS_INIT; - PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); - return SECFailure; - } - - gs->state = GS_DATA; - gs->offset = 0; - gs->inbuf.len = 0; - - if (gs->remainder > gs->inbuf.space) { - err = sslBuffer_Grow(&gs->inbuf, gs->remainder); - if (err) { /* realloc has set error code to no mem. */ - return err; - } - lbp = gs->inbuf.buf; - } - break; /* End this case. Continue around the loop. */ - - case GS_DATA: - /* - ** SSL3 record has been completely received. - */ - gs->state = GS_INIT; - return 1; - } - } - - return rv; -} - -/* - * Read in an entire DTLS record. - * - * Blocks here for blocking sockets, otherwise returns -1 with - * PR_WOULD_BLOCK_ERROR when socket would block. - * - * This is simpler than SSL because we are reading on a datagram socket - * and datagrams must contain >=1 complete records. - * - * returns 1 if received a complete DTLS record. - * returns 0 if recv returns EOF - * returns -1 if recv returns < 0 - * (The error value may have already been set to PR_WOULD_BLOCK_ERROR) - * - * Caller must hold the recv buf lock. - * - * This loop returns when either - * (a) an error or EOF occurs, - * (b) PR_WOULD_BLOCK_ERROR, - * (c) data (entire DTLS record) has been received. - */ -static int -dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) -{ - int nb; - int err; - int rv = 1; - - SSL_TRC(30, ("dtls_GatherData")); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - gs->state = GS_HEADER; - gs->offset = 0; - - if (gs->dtlsPacketOffset == gs->dtlsPacket.len) { /* No data left */ - gs->dtlsPacketOffset = 0; - gs->dtlsPacket.len = 0; - - /* Resize to the maximum possible size so we can fit a full datagram */ - /* This is the max fragment length for an encrypted fragment - ** plus the size of the record header. - ** This magic constant is copied from ssl3_GatherData, with 5 changed - ** to 13 (the size of the record header). - */ - if (gs->dtlsPacket.space < MAX_FRAGMENT_LENGTH + 2048 + 13) { - err = sslBuffer_Grow(&gs->dtlsPacket, - MAX_FRAGMENT_LENGTH + 2048 + 13); - if (err) { /* realloc has set error code to no mem. */ - return err; - } - } - - /* recv() needs to read a full datagram at a time */ - nb = ssl_DefRecv(ss, gs->dtlsPacket.buf, gs->dtlsPacket.space, flags); - - if (nb > 0) { - PRINT_BUF(60, (ss, "raw gather data:", gs->dtlsPacket.buf, nb)); - } else if (nb == 0) { - /* EOF */ - SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd)); - rv = 0; - return rv; - } else /* if (nb < 0) */ { - SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd, - PR_GetError())); - rv = SECFailure; - return rv; - } - - gs->dtlsPacket.len = nb; - } - - /* At this point we should have >=1 complete records lined up in - * dtlsPacket. Read off the header. - */ - if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < 13) { - SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet " - "too short to contain header", - SSL_GETPID(), ss->fd)); - PR_SetError(PR_WOULD_BLOCK_ERROR, 0); - gs->dtlsPacketOffset = 0; - gs->dtlsPacket.len = 0; - rv = SECFailure; - return rv; - } - memcpy(gs->hdr, gs->dtlsPacket.buf + gs->dtlsPacketOffset, 13); - gs->dtlsPacketOffset += 13; - - /* Have received SSL3 record header in gs->hdr. */ - gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12]; - - if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < gs->remainder) { - SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet too short " - "to contain rest of body", - SSL_GETPID(), ss->fd)); - PR_SetError(PR_WOULD_BLOCK_ERROR, 0); - gs->dtlsPacketOffset = 0; - gs->dtlsPacket.len = 0; - rv = SECFailure; - return rv; - } - - /* OK, we have at least one complete packet, copy into inbuf */ - if (gs->remainder > gs->inbuf.space) { - err = sslBuffer_Grow(&gs->inbuf, gs->remainder); - if (err) { /* realloc has set error code to no mem. */ - return err; - } - } - - memcpy(gs->inbuf.buf, gs->dtlsPacket.buf + gs->dtlsPacketOffset, - gs->remainder); - gs->inbuf.len = gs->remainder; - gs->offset = gs->remainder; - gs->dtlsPacketOffset += gs->remainder; - gs->state = GS_INIT; - - return 1; -} - -/* Gather in a record and when complete, Handle that record. - * Repeat this until the handshake is complete, - * or until application data is available. - * - * Returns 1 when the handshake is completed without error, or - * application data is available. - * Returns 0 if ssl3_GatherData hits EOF. - * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. - * Returns -2 on SECWouldBlock return from ssl3_HandleRecord. - * - * Called from ssl_GatherRecord1stHandshake in sslcon.c, - * and from SSL_ForceHandshake in sslsecur.c - * and from ssl3_GatherAppDataRecord below (<- DoRecv in sslsecur.c). - * - * Caller must hold the recv buf lock. - */ -int -ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) -{ - SSL3Ciphertext cText; - int rv; - PRBool keepGoing = PR_TRUE; - - SSL_TRC(30, ("ssl3_GatherCompleteHandshake")); - - /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake, - * which requires the 1stHandshakeLock, which must be acquired before the - * RecvBufLock. - */ - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - do { - PRBool handleRecordNow = PR_FALSE; - - ssl_GetSSL3HandshakeLock(ss); - - /* Without this, we may end up wrongly reporting - * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the - * peer while we are waiting to be restarted. - */ - if (ss->ssl3.hs.restartTarget) { - ssl_ReleaseSSL3HandshakeLock(ss); - PORT_SetError(PR_WOULD_BLOCK_ERROR); - return (int)SECFailure; - } - - /* Treat an empty msgState like a NULL msgState. (Most of the time - * when ssl3_HandleHandshake returns SECWouldBlock, it leaves - * behind a non-NULL but zero-length msgState). - * Test: async_cert_restart_server_sends_hello_request_first_in_separate_record - */ - if (ss->ssl3.hs.msgState.buf) { - if (ss->ssl3.hs.msgState.len == 0) { - ss->ssl3.hs.msgState.buf = NULL; - } else { - handleRecordNow = PR_TRUE; - } - } - - ssl_ReleaseSSL3HandshakeLock(ss); - - if (handleRecordNow) { - /* ssl3_HandleHandshake previously returned SECWouldBlock and the - * as-yet-unprocessed plaintext of that previous handshake record. - * We need to process it now before we overwrite it with the next - * handshake record. - */ - rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf); - } else { - /* bring in the next sslv3 record. */ - if (ss->recvdCloseNotify) { - /* RFC 5246 Section 7.2.1: - * Any data received after a closure alert is ignored. - */ - return 0; - } - if (!IS_DTLS(ss)) { - rv = ssl3_GatherData(ss, &ss->gs, flags); - } else { - rv = dtls_GatherData(ss, &ss->gs, flags); - - /* If we got a would block error, that means that no data was - * available, so we check the timer to see if it's time to - * retransmit */ - if (rv == SECFailure && - (PORT_GetError() == PR_WOULD_BLOCK_ERROR)) { - ssl_GetSSL3HandshakeLock(ss); - dtls_CheckTimer(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - /* Restore the error in case something succeeded */ - PORT_SetError(PR_WOULD_BLOCK_ERROR); - } - } - - if (rv <= 0) { - return rv; - } - - /* decipher it, and handle it if it's a handshake. - * If it's application data, ss->gs.buf will not be empty upon return. - * If it's a change cipher spec, alert, or handshake message, - * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess. - */ - cText.type = (SSL3ContentType)ss->gs.hdr[0]; - cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2]; - - if (IS_DTLS(ss)) { - int i; - - cText.version = dtls_DTLSVersionToTLSVersion(cText.version); - /* DTLS sequence number */ - cText.seq_num.high = 0; - cText.seq_num.low = 0; - for (i = 0; i < 4; i++) { - cText.seq_num.high <<= 8; - cText.seq_num.low <<= 8; - cText.seq_num.high |= ss->gs.hdr[3 + i]; - cText.seq_num.low |= ss->gs.hdr[7 + i]; - } - } - - cText.buf = &ss->gs.inbuf; - rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf); - } - if (rv < 0) { - return ss->recvdCloseNotify ? 0 : rv; - } - if (ss->gs.buf.len > 0) { - /* We have application data to return to the application. This - * prioritizes returning application data to the application over - * completing any renegotiation handshake we may be doing. - */ - PORT_Assert(ss->firstHsDone); - PORT_Assert(cText.type == content_application_data); - break; - } - - PORT_Assert(keepGoing); - ssl_GetSSL3HandshakeLock(ss); - if (ss->ssl3.hs.ws == idle_handshake) { - /* We are done with the current handshake so stop trying to - * handshake. Note that it would be safe to test ss->firstHsDone - * instead of ss->ssl3.hs.ws. By testing ss->ssl3.hs.ws instead, - * we prioritize completing a renegotiation handshake over sending - * application data. - */ - PORT_Assert(ss->firstHsDone); - PORT_Assert(!ss->ssl3.hs.canFalseStart); - keepGoing = PR_FALSE; - } else if (ss->ssl3.hs.canFalseStart) { - /* Prioritize sending application data over trying to complete - * the handshake if we're false starting. - * - * If we were to do this check at the beginning of the loop instead - * of here, then this function would become be a no-op after - * receiving the ServerHelloDone in the false start case, and we - * would never complete the handshake. - */ - PORT_Assert(!ss->firstHsDone); - - if (ssl3_WaitingForServerSecondRound(ss)) { - keepGoing = PR_FALSE; - } else { - ss->ssl3.hs.canFalseStart = PR_FALSE; - } - } - ssl_ReleaseSSL3HandshakeLock(ss); - } while (keepGoing); - - ss->gs.readOffset = 0; - ss->gs.writeOffset = ss->gs.buf.len; - return 1; -} - -/* Repeatedly gather in a record and when complete, Handle that record. - * Repeat this until some application data is received. - * - * Returns 1 when application data is available. - * Returns 0 if ssl3_GatherData hits EOF. - * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. - * Returns -2 on SECWouldBlock return from ssl3_HandleRecord. - * - * Called from DoRecv in sslsecur.c - * Caller must hold the recv buf lock. - */ -int -ssl3_GatherAppDataRecord(sslSocket *ss, int flags) -{ - int rv; - - /* ssl3_GatherCompleteHandshake requires both of these locks. */ - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - do { - rv = ssl3_GatherCompleteHandshake(ss, flags); - } while (rv > 0 && ss->gs.buf.len == 0); - - return rv; -}
diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h deleted file mode 100644 index 928d0596..0000000 --- a/net/third_party/nss/ssl/ssl3prot.h +++ /dev/null
@@ -1,323 +0,0 @@ -/* Private header file of libSSL. - * Various and sundry protocol constants. DON'T CHANGE THESE. These - * values are defined by the SSL 3.0 protocol specification. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __ssl3proto_h_ -#define __ssl3proto_h_ - -typedef PRUint8 SSL3Opaque; - -typedef PRUint16 SSL3ProtocolVersion; -/* version numbers are defined in sslproto.h */ - -/* The TLS 1.3 draft version. Used to avoid negotiating - * between incompatible pre-standard TLS 1.3 drafts. - * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */ -#define TLS_1_3_DRAFT_VERSION 11 - -typedef PRUint16 ssl3CipherSuite; -/* The cipher suites are defined in sslproto.h */ - -#define MAX_CERT_TYPES 10 -#define MAX_COMPRESSION_METHODS 10 -#define MAX_MAC_LENGTH 64 -#define MAX_PADDING_LENGTH 64 -#define MAX_KEY_LENGTH 64 -#define EXPORT_KEY_LENGTH 5 -#define SSL3_RANDOM_LENGTH 32 - -#define SSL3_RECORD_HEADER_LENGTH 5 - -/* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */ -#define DTLS_RECORD_HEADER_LENGTH 13 - -#define MAX_FRAGMENT_LENGTH 16384 - -typedef enum { - content_change_cipher_spec = 20, - content_alert = 21, - content_handshake = 22, - content_application_data = 23 -} SSL3ContentType; - -typedef struct { - SSL3ContentType type; - SSL3ProtocolVersion version; - PRUint16 length; - SECItem fragment; -} SSL3Plaintext; - -typedef struct { - SSL3ContentType type; - SSL3ProtocolVersion version; - PRUint16 length; - SECItem fragment; -} SSL3Compressed; - -typedef struct { - SECItem content; - SSL3Opaque MAC[MAX_MAC_LENGTH]; -} SSL3GenericStreamCipher; - -typedef struct { - SECItem content; - SSL3Opaque MAC[MAX_MAC_LENGTH]; - PRUint8 padding[MAX_PADDING_LENGTH]; - PRUint8 padding_length; -} SSL3GenericBlockCipher; - -typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice; - -typedef struct { - SSL3ChangeCipherSpecChoice choice; -} SSL3ChangeCipherSpec; - -typedef enum { alert_warning = 1, - alert_fatal = 2 } SSL3AlertLevel; - -typedef enum { - close_notify = 0, - unexpected_message = 10, - bad_record_mac = 20, - decryption_failed_RESERVED = 21, /* do not send; see RFC 5246 */ - record_overflow = 22, /* TLS only */ - decompression_failure = 30, - handshake_failure = 40, - no_certificate = 41, /* SSL3 only, NOT TLS */ - bad_certificate = 42, - unsupported_certificate = 43, - certificate_revoked = 44, - certificate_expired = 45, - certificate_unknown = 46, - illegal_parameter = 47, - - /* All alerts below are TLS only. */ - unknown_ca = 48, - access_denied = 49, - decode_error = 50, - decrypt_error = 51, - export_restriction = 60, - protocol_version = 70, - insufficient_security = 71, - internal_error = 80, - inappropriate_fallback = 86, /* could also be sent for SSLv3 */ - user_canceled = 90, - no_renegotiation = 100, - - /* Alerts for client hello extensions */ - missing_extension = 109, - unsupported_extension = 110, - certificate_unobtainable = 111, - unrecognized_name = 112, - bad_certificate_status_response = 113, - bad_certificate_hash_value = 114, - no_application_protocol = 120 - -} SSL3AlertDescription; - -typedef struct { - SSL3AlertLevel level; - SSL3AlertDescription description; -} SSL3Alert; - -typedef enum { - hello_request = 0, - client_hello = 1, - server_hello = 2, - hello_verify_request = 3, - new_session_ticket = 4, - hello_retry_request = 6, - encrypted_extensions = 8, - certificate = 11, - server_key_exchange = 12, - certificate_request = 13, - server_hello_done = 14, - certificate_verify = 15, - client_key_exchange = 16, - finished = 20, - certificate_status = 22, - next_proto = 67, - channelid_encrypted_extensions = 203 -} SSL3HandshakeType; - -typedef struct { - PRUint8 empty; -} SSL3HelloRequest; - -typedef struct { - SSL3Opaque rand[SSL3_RANDOM_LENGTH]; -} SSL3Random; - -typedef struct { - SSL3Opaque id[32]; - PRUint8 length; -} SSL3SessionID; - -typedef struct { - SSL3ProtocolVersion client_version; - SSL3Random random; - SSL3SessionID session_id; - SECItem cipher_suites; - PRUint8 cm_count; - SSLCompressionMethod compression_methods[MAX_COMPRESSION_METHODS]; -} SSL3ClientHello; - -typedef struct { - SSL3ProtocolVersion server_version; - SSL3Random random; - SSL3SessionID session_id; - ssl3CipherSuite cipher_suite; - SSLCompressionMethod compression_method; -} SSL3ServerHello; - -typedef struct { - SECItem list; -} SSL3Certificate; - -/* SSL3SignType moved to ssl.h */ - -/* The SSL key exchange method used */ -typedef enum { - kea_null, - kea_rsa, - kea_rsa_export, - kea_rsa_export_1024, - kea_dh_dss, - kea_dh_dss_export, - kea_dh_rsa, - kea_dh_rsa_export, - kea_dhe_dss, - kea_dhe_dss_export, - kea_dhe_rsa, - kea_dhe_rsa_export, - kea_dh_anon, - kea_dh_anon_export, - kea_rsa_fips, - kea_ecdh_ecdsa, - kea_ecdhe_ecdsa, - kea_ecdh_rsa, - kea_ecdhe_rsa, - kea_ecdh_anon -} SSL3KeyExchangeAlgorithm; - -typedef struct { - SECItem modulus; - SECItem exponent; -} SSL3ServerRSAParams; - -typedef struct { - SECItem p; - SECItem g; - SECItem Ys; -} SSL3ServerDHParams; - -typedef struct { - union { - SSL3ServerDHParams dh; - SSL3ServerRSAParams rsa; - } u; -} SSL3ServerParams; - -/* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS - * prior to 1.2. */ -typedef struct { - PRUint8 md5[16]; - PRUint8 sha[20]; -} SSL3HashesIndividually; - -/* SSL3Hashes contains an SSL hash value. The digest is contained in |u.raw| - * which, if |hashAlg==ssl_hash_none| is also a SSL3HashesIndividually - * struct. */ -typedef struct { - unsigned int len; - SSLHashType hashAlg; - union { - PRUint8 raw[64]; - SSL3HashesIndividually s; - } u; -} SSL3Hashes; - -typedef struct { - union { - SSL3Opaque anonymous; - SSL3Hashes certified; - } u; -} SSL3ServerKeyExchange; - -typedef enum { - ct_RSA_sign = 1, - ct_DSS_sign = 2, - ct_RSA_fixed_DH = 3, - ct_DSS_fixed_DH = 4, - ct_RSA_ephemeral_DH = 5, - ct_DSS_ephemeral_DH = 6, - ct_ECDSA_sign = 64, - ct_RSA_fixed_ECDH = 65, - ct_ECDSA_fixed_ECDH = 66 - -} SSL3ClientCertificateType; - -typedef struct { - SSL3Opaque client_version[2]; - SSL3Opaque random[46]; -} SSL3RSAPreMasterSecret; - -typedef SSL3Opaque SSL3MasterSecret[48]; - -typedef enum { - sender_client = 0x434c4e54, - sender_server = 0x53525652 -} SSL3Sender; - -typedef SSL3HashesIndividually SSL3Finished; - -typedef struct { - SSL3Opaque verify_data[12]; -} TLSFinished; - -/* - * TLS extension related data structures and constants. - */ - -/* SessionTicket extension related data structures. */ - -/* NewSessionTicket handshake message. */ -typedef struct { - PRUint32 received_timestamp; - PRUint32 ticket_lifetime_hint; - SECItem ticket; -} NewSessionTicket; - -typedef enum { - CLIENT_AUTH_ANONYMOUS = 0, - CLIENT_AUTH_CERTIFICATE = 1 -} ClientAuthenticationType; - -typedef struct { - ClientAuthenticationType client_auth_type; - union { - SSL3Opaque *certificate_list; - } identity; -} ClientIdentity; - -#define SESS_TICKET_KEY_NAME_LEN 16 -#define SESS_TICKET_KEY_NAME_PREFIX "NSS!" -#define SESS_TICKET_KEY_NAME_PREFIX_LEN 4 -#define SESS_TICKET_KEY_VAR_NAME_LEN 12 - -typedef struct { - unsigned char *key_name; - unsigned char *iv; - SECItem encrypted_state; - unsigned char *mac; -} EncryptedSessionTicket; - -#define TLS_EX_SESS_TICKET_MAC_LENGTH 32 - -#define TLS_STE_NO_SERVER_NAME -1 - -#endif /* __ssl3proto_h_ */
diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c deleted file mode 100644 index e78a513a..0000000 --- a/net/third_party/nss/ssl/sslauth.c +++ /dev/null
@@ -1,316 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "cert.h" -#include "secitem.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "pk11func.h" -#include "ocsp.h" - -/* NEED LOCKS IN HERE. */ -CERTCertificate * -SSL_PeerCertificate(PRFileDesc *fd) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate", - SSL_GETPID(), fd)); - return 0; - } - if (ss->opt.useSecurity && ss->sec.peerCert) { - return CERT_DupCertificate(ss->sec.peerCert); - } - return 0; -} - -/* NEED LOCKS IN HERE. */ -CERTCertList * -SSL_PeerCertificateChain(PRFileDesc *fd) -{ - sslSocket *ss; - CERTCertList *chain = NULL; - CERTCertificate *cert; - ssl3CertNode *cur; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", - SSL_GETPID(), fd)); - return NULL; - } - if (!ss->opt.useSecurity || !ss->sec.peerCert) { - PORT_SetError(SSL_ERROR_NO_CERTIFICATE); - return NULL; - } - chain = CERT_NewCertList(); - if (!chain) { - return NULL; - } - cert = CERT_DupCertificate(ss->sec.peerCert); - if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { - goto loser; - } - for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { - cert = CERT_DupCertificate(cur->cert); - if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { - goto loser; - } - } - return chain; - -loser: - CERT_DestroyCertList(chain); - return NULL; -} - -/* NEED LOCKS IN HERE. */ -CERTCertificate * -SSL_LocalCertificate(PRFileDesc *fd) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate", - SSL_GETPID(), fd)); - return NULL; - } - if (ss->opt.useSecurity) { - if (ss->sec.localCert) { - return CERT_DupCertificate(ss->sec.localCert); - } - if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) { - return CERT_DupCertificate(ss->sec.ci.sid->localCert); - } - } - return NULL; -} - -/* NEED LOCKS IN HERE. */ -SECStatus -SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1, - char **ip, char **sp) -{ - sslSocket *ss; - const char *cipherName; - PRBool isDes = PR_FALSE; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (cp) - *cp = 0; - if (kp0) - *kp0 = 0; - if (kp1) - *kp1 = 0; - if (ip) - *ip = 0; - if (sp) - *sp = 0; - if (op) { - *op = SSL_SECURITY_STATUS_OFF; - } - - if (ss->opt.useSecurity && ss->enoughFirstHsDone) { - if (ss->version < SSL_LIBRARY_VERSION_3_0) { - cipherName = ssl_cipherName[ss->sec.cipherType]; - } else { - cipherName = ssl3_cipherName[ss->sec.cipherType]; - } - PORT_Assert(cipherName); - if (cipherName) { - if (PORT_Strstr(cipherName, "DES")) - isDes = PR_TRUE; - - if (cp) { - *cp = PORT_Strdup(cipherName); - } - } - - if (kp0) { - *kp0 = ss->sec.keyBits; - if (isDes) - *kp0 = (*kp0 * 7) / 8; - } - if (kp1) { - *kp1 = ss->sec.secretKeyBits; - if (isDes) - *kp1 = (*kp1 * 7) / 8; - } - if (op) { - if (ss->sec.keyBits == 0) { - *op = SSL_SECURITY_STATUS_OFF; - } else if (ss->sec.secretKeyBits < 90) { - *op = SSL_SECURITY_STATUS_ON_LOW; - } else { - *op = SSL_SECURITY_STATUS_ON_HIGH; - } - } - - if (ip || sp) { - CERTCertificate *cert; - - cert = ss->sec.peerCert; - if (cert) { - if (ip) { - *ip = CERT_NameToAscii(&cert->issuer); - } - if (sp) { - *sp = CERT_NameToAscii(&cert->subject); - } - } else { - if (ip) { - *ip = PORT_Strdup("no certificate"); - } - if (sp) { - *sp = PORT_Strdup("no certificate"); - } - } - } - } - - return SECSuccess; -} - -/************************************************************************/ - -/* NEED LOCKS IN HERE. */ -SECStatus -SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg) -{ - sslSocket *ss; - - ss = ssl_FindSocket(s); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook", - SSL_GETPID(), s)); - return SECFailure; - } - - ss->authCertificate = func; - ss->authCertificateArg = arg; - - return SECSuccess; -} - -/* NEED LOCKS IN HERE. */ -SECStatus -SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, - void *arg) -{ - sslSocket *ss; - - ss = ssl_FindSocket(s); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", - SSL_GETPID(), s)); - return SECFailure; - } - - ss->getClientAuthData = func; - ss->getClientAuthDataArg = arg; - return SECSuccess; -} - -SECStatus -SSL_SetClientChannelIDCallback(PRFileDesc *fd, - SSLClientChannelIDCallback callback, - void *arg) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback", - SSL_GETPID(), fd)); - return SECFailure; - } - - ss->getChannelID = callback; - ss->getChannelIDArg = arg; - - return SECSuccess; -} - -/* NEED LOCKS IN HERE. */ -SECStatus -SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) -{ - sslSocket *ss; - - ss = ssl_FindSocket(s); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", - SSL_GETPID(), s)); - return SECFailure; - } - - ss->pkcs11PinArg = arg; - return SECSuccess; -} - -/* This is the "default" authCert callback function. It is called when a - * certificate message is received from the peer and the local application - * has not registered an authCert callback function. - */ -SECStatus -SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) -{ - SECStatus rv; - CERTCertDBHandle *handle; - sslSocket *ss; - SECCertUsage certUsage; - const char *hostname = NULL; - PRTime now = PR_Now(); - SECItemArray *certStatusArray; - - ss = ssl_FindSocket(fd); - PORT_Assert(ss != NULL); - if (!ss) { - return SECFailure; - } - - handle = (CERTCertDBHandle *)arg; - certStatusArray = &ss->sec.ci.sid->peerCertStatus; - - if (certStatusArray->len) { - PORT_SetError(0); - if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now, - &certStatusArray->items[0], - ss->pkcs11PinArg) != - SECSuccess) { - PORT_Assert(PR_GetError() != 0); - } - } - - /* this may seem backwards, but isn't. */ - certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; - - rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage, - now, ss->pkcs11PinArg, NULL); - - if (rv != SECSuccess || isServer) - return rv; - - /* cert is OK. This is the client side of an SSL connection. - * Now check the name field in the cert against the desired hostname. - * NB: This is our only defense against Man-In-The-Middle (MITM) attacks! - */ - hostname = ss->url; - if (hostname && hostname[0]) - rv = CERT_VerifyCertName(ss->sec.peerCert, hostname); - else - rv = SECFailure; - if (rv != SECSuccess) - PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); - - return rv; -}
diff --git a/net/third_party/nss/ssl/sslcon.c b/net/third_party/nss/ssl/sslcon.c deleted file mode 100644 index 95d27275..0000000 --- a/net/third_party/nss/ssl/sslcon.c +++ /dev/null
@@ -1,3688 +0,0 @@ -/* - * SSL v2 handshake functions, and functions common to SSL2 and SSL3. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nssrenam.h" -#include "cert.h" -#include "secitem.h" -#include "sechash.h" -#include "cryptohi.h" /* for SGN_ funcs */ -#include "keyhi.h" /* for SECKEY_ high level functions. */ -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "ssl3prot.h" -#include "sslerr.h" -#include "pk11func.h" -#include "prinit.h" -#include "prtime.h" /* for PR_Now() */ - -static PRBool policyWasSet; - -#define ssl2_NUM_SUITES_IMPLEMENTED 6 - -/* This list is sent back to the client when the client-hello message - * contains no overlapping ciphers, so the client can report what ciphers - * are supported by the server. Unlike allCipherSuites (above), this list - * is sorted by descending preference, not by cipherSuite number. - */ -/* clang-format off */ -static const PRUint8 implementedCipherSuites[ssl2_NUM_SUITES_IMPLEMENTED * 3] = { - SSL_CK_RC4_128_WITH_MD5, 0x00, 0x80, - SSL_CK_RC2_128_CBC_WITH_MD5, 0x00, 0x80, - SSL_CK_DES_192_EDE3_CBC_WITH_MD5, 0x00, 0xC0, - SSL_CK_DES_64_CBC_WITH_MD5, 0x00, 0x40, - SSL_CK_RC4_128_EXPORT40_WITH_MD5, 0x00, 0x80, - SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, 0x00, 0x80 -}; - - -typedef struct ssl2SpecsStr { - PRUint8 nkm; /* do this many hashes to generate key material. */ - PRUint8 nkd; /* size of readKey and writeKey in bytes. */ - PRUint8 blockSize; - PRUint8 blockShift; - CK_MECHANISM_TYPE mechanism; - PRUint8 keyLen; /* cipher symkey size in bytes. */ - PRUint8 pubLen; /* publicly reveal this many bytes of key. */ - PRUint8 ivLen; /* length of IV data at *ca. */ -} ssl2Specs; - -static const ssl2Specs ssl_Specs[] = { - /* NONE */ - { 0, 0, 0, 0 }, - /* SSL_CK_RC4_128_WITH_MD5 */ - { 2, 16, 1, 0, CKM_RC4, 16, 0, 0 }, - /* SSL_CK_RC4_128_EXPORT40_WITH_MD5 */ - { 2, 16, 1, 0, CKM_RC4, 16, 11, 0 }, - /* SSL_CK_RC2_128_CBC_WITH_MD5 */ - { 2, 16, 8, 3, CKM_RC2_CBC, 16, 0, 8 }, - /* SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 */ - { 2, 16, 8, 3, CKM_RC2_CBC, 16, 11, 8 }, - /* SSL_CK_IDEA_128_CBC_WITH_MD5 */ - { 0, 0, 0, 0 }, - /* SSL_CK_DES_64_CBC_WITH_MD5 */ - { 1, 8, 8, 3, CKM_DES_CBC, 8, 0, 8 }, - /* SSL_CK_DES_192_EDE3_CBC_WITH_MD5 */ - { 3, 24, 8, 3, CKM_DES3_CBC, 24, 0, 8 }, -}; -/* clang-format on */ - -#define SET_ERROR_CODE /* reminder */ -#define TEST_FOR_FAILURE /* reminder */ - -/* -** Put a string tag in the library so that we can examine an executable -** and see what kind of security it supports. -*/ -const char *ssl_version = "SECURITY_VERSION:" - " +us" - " +export" -#ifdef TRACE - " +trace" -#endif -#ifdef DEBUG - " +debug" -#endif - ; - -const char *const ssl_cipherName[] = { - "unknown", - "RC4", - "RC4-Export", - "RC2-CBC", - "RC2-CBC-Export", - "IDEA-CBC", - "DES-CBC", - "DES-EDE3-CBC", - "unknown", - "unknown", /* was fortezza, NO LONGER USED */ -}; - -/* bit-masks, showing which SSLv2 suites are allowed. - * lsb corresponds to first cipher suite in allCipherSuites[]. - */ -static PRUint16 allowedByPolicy; /* all off by default */ -static PRUint16 maybeAllowedByPolicy; /* all off by default */ -static PRUint16 chosenPreference = 0xff; /* all on by default */ - -/* bit values for the above two bit masks */ -#define SSL_CB_RC4_128_WITH_MD5 (1 << SSL_CK_RC4_128_WITH_MD5) -#define SSL_CB_RC4_128_EXPORT40_WITH_MD5 (1 << SSL_CK_RC4_128_EXPORT40_WITH_MD5) -#define SSL_CB_RC2_128_CBC_WITH_MD5 (1 << SSL_CK_RC2_128_CBC_WITH_MD5) -#define SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 (1 << SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5) -#define SSL_CB_IDEA_128_CBC_WITH_MD5 (1 << SSL_CK_IDEA_128_CBC_WITH_MD5) -#define SSL_CB_DES_64_CBC_WITH_MD5 (1 << SSL_CK_DES_64_CBC_WITH_MD5) -#define SSL_CB_DES_192_EDE3_CBC_WITH_MD5 (1 << SSL_CK_DES_192_EDE3_CBC_WITH_MD5) -#define SSL_CB_IMPLEMENTED \ - (SSL_CB_RC4_128_WITH_MD5 | \ - SSL_CB_RC4_128_EXPORT40_WITH_MD5 | \ - SSL_CB_RC2_128_CBC_WITH_MD5 | \ - SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 | \ - SSL_CB_DES_64_CBC_WITH_MD5 | \ - SSL_CB_DES_192_EDE3_CBC_WITH_MD5) - -/* Construct a socket's list of cipher specs from the global default values. - */ -static SECStatus -ssl2_ConstructCipherSpecs(sslSocket *ss) -{ - PRUint8 *cs = NULL; - unsigned int allowed; - unsigned int count; - int ssl3_count = 0; - int final_count; - int i; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - count = 0; - PORT_Assert(ss != 0); - allowed = !ss->opt.enableSSL2 ? 0 : (ss->allowedByPolicy & - ss->chosenPreference & SSL_CB_IMPLEMENTED); - while (allowed) { - if (allowed & 1) - ++count; - allowed >>= 1; - } - - /* Call ssl3_config_match_init() once here, - * instead of inside ssl3_ConstructV2CipherSpecsHack(), - * because the latter gets called twice below, - * and then again in ssl2_BeginClientHandshake(). - */ - ssl3_config_match_init(ss); - - /* ask SSL3 how many cipher suites it has. */ - rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3_count); - if (rv < 0) - return rv; - count += ssl3_count; - - /* Allocate memory to hold cipher specs */ - if (count > 0) - cs = (PRUint8 *)PORT_Alloc(count * 3); - else - PORT_SetError(SSL_ERROR_SSL_DISABLED); - if (cs == NULL) - return SECFailure; - - if (ss->cipherSpecs != NULL) { - PORT_Free(ss->cipherSpecs); - } - ss->cipherSpecs = cs; - ss->sizeCipherSpecs = count * 3; - - /* fill in cipher specs for SSL2 cipher suites */ - allowed = !ss->opt.enableSSL2 ? 0 : (ss->allowedByPolicy & - ss->chosenPreference & SSL_CB_IMPLEMENTED); - for (i = 0; i < ssl2_NUM_SUITES_IMPLEMENTED * 3; i += 3) { - const PRUint8 *hs = implementedCipherSuites + i; - int ok = allowed & (1U << hs[0]); - if (ok) { - cs[0] = hs[0]; - cs[1] = hs[1]; - cs[2] = hs[2]; - cs += 3; - } - } - - /* now have SSL3 add its suites onto the end */ - rv = ssl3_ConstructV2CipherSpecsHack(ss, cs, &final_count); - - /* adjust for any difference between first pass and second pass */ - ss->sizeCipherSpecs -= (ssl3_count - final_count) * 3; - - return rv; -} - -/* This function is called immediately after ssl2_ConstructCipherSpecs() -** at the beginning of a handshake. It detects cases where a protocol -** (e.g. SSL2 or SSL3) is logically enabled, but all its cipher suites -** for that protocol have been disabled. If such cases, it clears the -** enable bit for the protocol. If no protocols remain enabled, or -** if no cipher suites are found, it sets the error code and returns -** SECFailure, otherwise it returns SECSuccess. -*/ -static SECStatus -ssl2_CheckConfigSanity(sslSocket *ss) -{ - unsigned int allowed; - int ssl3CipherCount = 0; - SECStatus rv; - - /* count the SSL2 and SSL3 enabled ciphers. - * if either is zero, clear the socket's enable for that protocol. - */ - if (!ss->cipherSpecs) - goto disabled; - - allowed = ss->allowedByPolicy & ss->chosenPreference; - if (!allowed) - ss->opt.enableSSL2 = PR_FALSE; /* not really enabled if no ciphers */ - - /* ssl3_config_match_init was called in ssl2_ConstructCipherSpecs(). */ - /* Ask how many ssl3 CipherSuites were enabled. */ - rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3CipherCount); - if (rv != SECSuccess || ssl3CipherCount <= 0) { - /* SSL3/TLS not really enabled if no ciphers */ - ss->vrange.min = SSL_LIBRARY_VERSION_NONE; - ss->vrange.max = SSL_LIBRARY_VERSION_NONE; - } - - if (!ss->opt.enableSSL2 && SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.", - SSL_GETPID(), ss->fd)); - disabled: - PORT_SetError(SSL_ERROR_SSL_DISABLED); - return SECFailure; - } - return SECSuccess; -} - -/* - * Since this is a global (not per-socket) setting, we cannot use the - * HandshakeLock to protect this. Probably want a global lock. - */ -SECStatus -ssl2_SetPolicy(PRInt32 which, PRInt32 policy) -{ - PRUint32 bitMask; - SECStatus rv = SECSuccess; - - which &= 0x000f; - bitMask = 1 << which; - - if (!(bitMask & SSL_CB_IMPLEMENTED)) { - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - return SECFailure; - } - - if (policy == SSL_ALLOWED) { - allowedByPolicy |= bitMask; - maybeAllowedByPolicy |= bitMask; - } else if (policy == SSL_RESTRICTED) { - allowedByPolicy &= ~bitMask; - maybeAllowedByPolicy |= bitMask; - } else { - allowedByPolicy &= ~bitMask; - maybeAllowedByPolicy &= ~bitMask; - } - allowedByPolicy &= SSL_CB_IMPLEMENTED; - maybeAllowedByPolicy &= SSL_CB_IMPLEMENTED; - - policyWasSet = PR_TRUE; - return rv; -} - -SECStatus -ssl2_GetPolicy(PRInt32 which, PRInt32 *oPolicy) -{ - PRUint32 bitMask; - PRInt32 policy; - - which &= 0x000f; - bitMask = 1 << which; - - /* Caller assures oPolicy is not null. */ - if (!(bitMask & SSL_CB_IMPLEMENTED)) { - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - *oPolicy = SSL_NOT_ALLOWED; - return SECFailure; - } - - if (maybeAllowedByPolicy & bitMask) { - policy = (allowedByPolicy & bitMask) ? SSL_ALLOWED : SSL_RESTRICTED; - } else { - policy = SSL_NOT_ALLOWED; - } - - *oPolicy = policy; - return SECSuccess; -} - -/* - * Since this is a global (not per-socket) setting, we cannot use the - * HandshakeLock to protect this. Probably want a global lock. - * Called from SSL_CipherPrefSetDefault in sslsock.c - * These changes have no effect on any sslSockets already created. - */ -SECStatus -ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled) -{ - PRUint32 bitMask; - - which &= 0x000f; - bitMask = 1 << which; - - if (!(bitMask & SSL_CB_IMPLEMENTED)) { - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - return SECFailure; - } - - if (enabled) - chosenPreference |= bitMask; - else - chosenPreference &= ~bitMask; - chosenPreference &= SSL_CB_IMPLEMENTED; - - return SECSuccess; -} - -SECStatus -ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled) -{ - PRBool rv = PR_FALSE; - PRUint32 bitMask; - - which &= 0x000f; - bitMask = 1 << which; - - if (!(bitMask & SSL_CB_IMPLEMENTED)) { - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - *enabled = PR_FALSE; - return SECFailure; - } - - rv = (PRBool)((chosenPreference & bitMask) != 0); - *enabled = rv; - return SECSuccess; -} - -SECStatus -ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled) -{ - PRUint32 bitMask; - - which &= 0x000f; - bitMask = 1 << which; - - if (!(bitMask & SSL_CB_IMPLEMENTED)) { - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - return SECFailure; - } - - if (enabled) - ss->chosenPreference |= bitMask; - else - ss->chosenPreference &= ~bitMask; - ss->chosenPreference &= SSL_CB_IMPLEMENTED; - - return SECSuccess; -} - -SECStatus -ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled) -{ - PRBool rv = PR_FALSE; - PRUint32 bitMask; - - which &= 0x000f; - bitMask = 1 << which; - - if (!(bitMask & SSL_CB_IMPLEMENTED)) { - PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE); - *enabled = PR_FALSE; - return SECFailure; - } - - rv = (PRBool)((ss->chosenPreference & bitMask) != 0); - *enabled = rv; - return SECSuccess; -} - -/* copy global default policy into socket. */ -void -ssl2_InitSocketPolicy(sslSocket *ss) -{ - ss->allowedByPolicy = allowedByPolicy; - ss->maybeAllowedByPolicy = maybeAllowedByPolicy; - ss->chosenPreference = chosenPreference; -} - -/************************************************************************/ - -/* Called from ssl2_CreateSessionCypher(), which already holds handshake lock. - */ -static SECStatus -ssl2_CreateMAC(sslSecurityInfo *sec, SECItem *readKey, SECItem *writeKey, - int cipherChoice) -{ - switch (cipherChoice) { - case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: - case SSL_CK_RC2_128_CBC_WITH_MD5: - case SSL_CK_RC4_128_EXPORT40_WITH_MD5: - case SSL_CK_RC4_128_WITH_MD5: - case SSL_CK_DES_64_CBC_WITH_MD5: - case SSL_CK_DES_192_EDE3_CBC_WITH_MD5: - sec->hash = HASH_GetHashObject(HASH_AlgMD5); - if (SECITEM_CopyItem(0, &sec->sendSecret, writeKey) || - SECITEM_CopyItem(0, &sec->rcvSecret, readKey)) { - return SECFailure; - } - break; - - default: - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return SECFailure; - } - sec->hashcx = (*sec->hash->create)(); - if (sec->hashcx == NULL) - return SECFailure; - return SECSuccess; -} - -/************************************************************************ - * All the Send functions below must acquire and release the socket's - * xmitBufLock. - */ - -/* Called from all the Send* functions below. */ -static SECStatus -ssl2_GetSendBuffer(sslSocket *ss, unsigned int len) -{ - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - if (len < 128) { - len = 128; - } - if (len > ss->sec.ci.sendBuf.space) { - rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, len); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL[%d]: ssl2_GetSendBuffer failed, tried to get %d bytes", - SSL_GETPID(), ss->fd, len)); - rv = SECFailure; - } - } - return rv; -} - -/* Called from: - * ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage() - * ssl2_HandleRequestCertificate() <- ssl2_HandleMessage() - <- ssl_Do1stHandshake() - * ssl2_HandleMessage() <- ssl_Do1stHandshake() - * ssl2_HandleServerHelloMessage() <- ssl_Do1stHandshake() - after ssl2_BeginClientHandshake() - * ssl2_HandleClientHelloMessage() <- ssl_Do1stHandshake() - after ssl2_BeginServerHandshake() - * - * Acquires and releases the socket's xmitBufLock. - */ -int -ssl2_SendErrorMessage(sslSocket *ss, int error) -{ - int rv; - PRUint8 msg[SSL_HL_ERROR_HBYTES]; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - msg[0] = SSL_MT_ERROR; - msg[1] = MSB(error); - msg[2] = LSB(error); - - ssl_GetXmitBufLock(ss); /***************************************/ - - SSL_TRC(3, ("%d: SSL[%d]: sending error %d", SSL_GETPID(), ss->fd, error)); - - ss->handshakeBegun = 1; - rv = (*ss->sec.send)(ss, msg, sizeof(msg), 0); - if (rv >= 0) { - rv = SECSuccess; - } - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/* Called from ssl2_TryToFinish(). - * Acquires and releases the socket's xmitBufLock. - */ -static SECStatus -ssl2_SendClientFinishedMessage(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - int sent; - PRUint8 msg[1 + SSL_CONNECTIONID_BYTES]; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetXmitBufLock(ss); /***************************************/ - - if (ss->sec.ci.sentFinished == 0) { - ss->sec.ci.sentFinished = 1; - - SSL_TRC(3, ("%d: SSL[%d]: sending client-finished", - SSL_GETPID(), ss->fd)); - - msg[0] = SSL_MT_CLIENT_FINISHED; - PORT_Memcpy(msg + 1, ss->sec.ci.connectionID, - sizeof(ss->sec.ci.connectionID)); - - DUMP_MSG(29, (ss, msg, 1 + sizeof(ss->sec.ci.connectionID))); - sent = (*ss->sec.send)(ss, msg, 1 + sizeof(ss->sec.ci.connectionID), 0); - rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; - } - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/* Called from - * ssl2_HandleClientSessionKeyMessage() <- ssl2_HandleClientHelloMessage() - * ssl2_HandleClientHelloMessage() <- ssl_Do1stHandshake() - after ssl2_BeginServerHandshake() - * Acquires and releases the socket's xmitBufLock. - */ -static SECStatus -ssl2_SendServerVerifyMessage(sslSocket *ss) -{ - PRUint8 *msg; - int sendLen; - int sent; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetXmitBufLock(ss); /***************************************/ - - sendLen = 1 + SSL_CHALLENGE_BYTES; - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv != SECSuccess) { - goto done; - } - - msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_SERVER_VERIFY; - PORT_Memcpy(msg + 1, ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES); - - DUMP_MSG(29, (ss, msg, sendLen)); - sent = (*ss->sec.send)(ss, msg, sendLen, 0); - - rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; - -done: - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/* Called from ssl2_TryToFinish(). - * Acquires and releases the socket's xmitBufLock. - */ -static SECStatus -ssl2_SendServerFinishedMessage(sslSocket *ss) -{ - sslSessionID *sid; - PRUint8 *msg; - int sendLen, sent; - SECStatus rv = SECSuccess; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetXmitBufLock(ss); /***************************************/ - - if (ss->sec.ci.sentFinished == 0) { - ss->sec.ci.sentFinished = 1; - PORT_Assert(ss->sec.ci.sid != 0); - sid = ss->sec.ci.sid; - - SSL_TRC(3, ("%d: SSL[%d]: sending server-finished", - SSL_GETPID(), ss->fd)); - - sendLen = 1 + sizeof(sid->u.ssl2.sessionID); - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv != SECSuccess) { - goto done; - } - - msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_SERVER_FINISHED; - PORT_Memcpy(msg + 1, sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID)); - - DUMP_MSG(29, (ss, msg, sendLen)); - sent = (*ss->sec.send)(ss, msg, sendLen, 0); - - if (sent < 0) { - /* If send failed, it is now a bogus session-id */ - if (ss->sec.uncache) - (*ss->sec.uncache)(sid); - rv = (SECStatus)sent; - } else if (!ss->opt.noCache) { - if (sid->cached == never_cached) { - (*ss->sec.cache)(sid); - } - rv = SECSuccess; - } - ssl_FreeSID(sid); - ss->sec.ci.sid = 0; - } -done: - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/* Called from ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage() - * after ssl2_BeginClientHandshake() - * Acquires and releases the socket's xmitBufLock. - */ -static SECStatus -ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keySize, - PRUint8 *ca, int caLen, - PRUint8 *ck, int ckLen, - PRUint8 *ek, int ekLen) -{ - PRUint8 *msg; - int sendLen; - int sent; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetXmitBufLock(ss); /***************************************/ - - sendLen = SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen; - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv != SECSuccess) - goto done; - - SSL_TRC(3, ("%d: SSL[%d]: sending client-session-key", - SSL_GETPID(), ss->fd)); - - msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_CLIENT_MASTER_KEY; - msg[1] = cipher; - msg[2] = MSB(keySize); - msg[3] = LSB(keySize); - msg[4] = MSB(ckLen); - msg[5] = LSB(ckLen); - msg[6] = MSB(ekLen); - msg[7] = LSB(ekLen); - msg[8] = MSB(caLen); - msg[9] = LSB(caLen); - PORT_Memcpy(msg + SSL_HL_CLIENT_MASTER_KEY_HBYTES, ck, ckLen); - PORT_Memcpy(msg + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen, ek, ekLen); - PORT_Memcpy(msg + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen, ca, caLen); - - DUMP_MSG(29, (ss, msg, sendLen)); - sent = (*ss->sec.send)(ss, msg, sendLen, 0); - rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; -done: - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/* Called from ssl2_TriggerNextMessage() <- ssl2_HandleMessage() - * Acquires and releases the socket's xmitBufLock. - */ -static SECStatus -ssl2_SendCertificateRequestMessage(sslSocket *ss) -{ - PRUint8 *msg; - int sent; - int sendLen; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetXmitBufLock(ss); /***************************************/ - - sendLen = SSL_HL_REQUEST_CERTIFICATE_HBYTES + SSL_CHALLENGE_BYTES; - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv != SECSuccess) - goto done; - - SSL_TRC(3, ("%d: SSL[%d]: sending certificate request", - SSL_GETPID(), ss->fd)); - - /* Generate random challenge for client to encrypt */ - PK11_GenerateRandom(ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES); - - msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_REQUEST_CERTIFICATE; - msg[1] = SSL_AT_MD5_WITH_RSA_ENCRYPTION; - PORT_Memcpy(msg + SSL_HL_REQUEST_CERTIFICATE_HBYTES, - ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES); - - DUMP_MSG(29, (ss, msg, sendLen)); - sent = (*ss->sec.send)(ss, msg, sendLen, 0); - rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; -done: - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/* Called from ssl2_HandleRequestCertificate() <- ssl2_HandleMessage() - * Acquires and releases the socket's xmitBufLock. - */ -static int -ssl2_SendCertificateResponseMessage(sslSocket *ss, SECItem *cert, - SECItem *encCode) -{ - PRUint8 *msg; - int rv, sendLen; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetXmitBufLock(ss); /***************************************/ - - sendLen = SSL_HL_CLIENT_CERTIFICATE_HBYTES + encCode->len + cert->len; - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv) - goto done; - - SSL_TRC(3, ("%d: SSL[%d]: sending certificate response", - SSL_GETPID(), ss->fd)); - - msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_CLIENT_CERTIFICATE; - msg[1] = SSL_CT_X509_CERTIFICATE; - msg[2] = MSB(cert->len); - msg[3] = LSB(cert->len); - msg[4] = MSB(encCode->len); - msg[5] = LSB(encCode->len); - PORT_Memcpy(msg + SSL_HL_CLIENT_CERTIFICATE_HBYTES, cert->data, cert->len); - PORT_Memcpy(msg + SSL_HL_CLIENT_CERTIFICATE_HBYTES + cert->len, - encCode->data, encCode->len); - - DUMP_MSG(29, (ss, msg, sendLen)); - rv = (*ss->sec.send)(ss, msg, sendLen, 0); - if (rv >= 0) { - rv = SECSuccess; - } -done: - ssl_ReleaseXmitBufLock(ss); /***************************************/ - return rv; -} - -/******************************************************************** -** Send functions above this line must aquire & release the socket's -** xmitBufLock. -** All the ssl2_Send functions below this line are called vis ss->sec.send -** and require that the caller hold the xmitBufLock. -*/ - -/* -** Called from ssl2_SendStream, ssl2_SendBlock, but not from ssl2_SendClear. -*/ -static SECStatus -ssl2_CalcMAC(PRUint8 *result, - sslSecurityInfo *sec, - const PRUint8 *data, - unsigned int dataLen, - unsigned int paddingLen) -{ - const PRUint8 *secret = sec->sendSecret.data; - unsigned int secretLen = sec->sendSecret.len; - unsigned long sequenceNumber = sec->sendSequence; - unsigned int nout; - PRUint8 seq[4]; - PRUint8 padding[32]; /* XXX max blocksize? */ - - if (!sec->hash || !sec->hash->length) - return SECSuccess; - if (!sec->hashcx) - return SECFailure; - - /* Reset hash function */ - (*sec->hash->begin)(sec->hashcx); - - /* Feed hash the data */ - (*sec->hash->update)(sec->hashcx, secret, secretLen); - (*sec->hash->update)(sec->hashcx, data, dataLen); - PORT_Memset(padding, paddingLen, paddingLen); - (*sec->hash->update)(sec->hashcx, padding, paddingLen); - - seq[0] = (PRUint8)(sequenceNumber >> 24); - seq[1] = (PRUint8)(sequenceNumber >> 16); - seq[2] = (PRUint8)(sequenceNumber >> 8); - seq[3] = (PRUint8)(sequenceNumber); - - PRINT_BUF(60, (0, "calc-mac secret:", secret, secretLen)); - PRINT_BUF(60, (0, "calc-mac data:", data, dataLen)); - PRINT_BUF(60, (0, "calc-mac padding:", padding, paddingLen)); - PRINT_BUF(60, (0, "calc-mac seq:", seq, 4)); - - (*sec->hash->update)(sec->hashcx, seq, 4); - - /* Get result */ - (*sec->hash->end)(sec->hashcx, result, &nout, sec->hash->length); - - return SECSuccess; -} - -/* -** Maximum transmission amounts. These are tiny bit smaller than they -** need to be (they account for the MAC length plus some padding), -** assuming the MAC is 16 bytes long and the padding is a max of 7 bytes -** long. This gives an additional 9 bytes of slop to work within. -*/ -#define MAX_STREAM_CYPHER_LEN 0x7fe0 -#define MAX_BLOCK_CYPHER_LEN 0x3fe0 - -/* -** Send some data in the clear. -** Package up data with the length header and send it. -** -** Return count of bytes successfully written, or negative number (failure). -*/ -static PRInt32 -ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) -{ - PRUint8 *out; - int rv; - unsigned int amount; - int count = 0; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes in the clear", - SSL_GETPID(), ss->fd, len)); - PRINT_BUF(50, (ss, "clear data:", (PRUint8 *)in, len)); - - while (len) { - amount = PR_MIN(len, MAX_STREAM_CYPHER_LEN); - if (amount + 2 > ss->sec.writeBuf.space) { - rv = sslBuffer_Grow(&ss->sec.writeBuf, amount + 2); - if (rv != SECSuccess) { - count = rv; - break; - } - } - out = ss->sec.writeBuf.buf; - - /* - ** Construct message. - */ - out[0] = 0x80 | MSB(amount); - out[1] = LSB(amount); - PORT_Memcpy(&out[2], in, amount); - - /* Now send the data */ - rv = ssl_DefSend(ss, out, amount + 2, flags & ~ssl_SEND_FLAG_MASK); - if (rv < 0) { - if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) { - rv = 0; - } else { - /* Return short write if some data already went out... */ - if (count == 0) - count = rv; - break; - } - } - - if ((unsigned)rv < (amount + 2)) { - /* Short write. Save the data and return. */ - if (ssl_SaveWriteData(ss, out + rv, amount + 2 - rv) == - SECFailure) { - count = SECFailure; - } else { - count += amount; - ss->sec.sendSequence++; - } - break; - } - - ss->sec.sendSequence++; - in += amount; - count += amount; - len -= amount; - } - - return count; -} - -/* -** Send some data, when using a stream cipher. Stream ciphers have a -** block size of 1. Package up the data with the length header -** and send it. -*/ -static PRInt32 -ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) -{ - PRUint8 *out; - int rv; - int count = 0; - - int amount; - PRUint8 macLen; - int nout; - unsigned int buflen; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using stream cipher", - SSL_GETPID(), ss->fd, len)); - PRINT_BUF(50, (ss, "clear data:", (PRUint8 *)in, len)); - - while (len) { - ssl_GetSpecReadLock(ss); /*************************************/ - - macLen = ss->sec.hash->length; - amount = PR_MIN(len, MAX_STREAM_CYPHER_LEN); - buflen = amount + 2 + macLen; - if (buflen > ss->sec.writeBuf.space) { - rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen); - if (rv != SECSuccess) { - goto loser; - } - } - out = ss->sec.writeBuf.buf; - nout = amount + macLen; - out[0] = 0x80 | MSB(nout); - out[1] = LSB(nout); - - /* Calculate MAC */ - rv = ssl2_CalcMAC(out + 2, /* put MAC here */ - &ss->sec, - in, amount, /* input addr & length */ - 0); /* no padding */ - if (rv != SECSuccess) - goto loser; - - /* Encrypt MAC */ - rv = (*ss->sec.enc)(ss->sec.writecx, out + 2, &nout, macLen, out + 2, macLen); - if (rv) - goto loser; - - /* Encrypt data from caller */ - rv = (*ss->sec.enc)(ss->sec.writecx, out + 2 + macLen, &nout, amount, in, amount); - if (rv) - goto loser; - - ssl_ReleaseSpecReadLock(ss); /*************************************/ - - PRINT_BUF(50, (ss, "encrypted data:", out, buflen)); - - rv = ssl_DefSend(ss, out, buflen, flags & ~ssl_SEND_FLAG_MASK); - if (rv < 0) { - if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) { - SSL_TRC(50, ("%d: SSL[%d]: send stream would block, " - "saving data", - SSL_GETPID(), ss->fd)); - rv = 0; - } else { - SSL_TRC(10, ("%d: SSL[%d]: send stream error %d", - SSL_GETPID(), ss->fd, PORT_GetError())); - /* Return short write if some data already went out... */ - if (count == 0) - count = rv; - goto done; - } - } - - if ((unsigned)rv < buflen) { - /* Short write. Save the data and return. */ - if (ssl_SaveWriteData(ss, out + rv, buflen - rv) == SECFailure) { - count = SECFailure; - } else { - count += amount; - ss->sec.sendSequence++; - } - goto done; - } - - ss->sec.sendSequence++; - in += amount; - count += amount; - len -= amount; - } - -done: - return count; - -loser: - ssl_ReleaseSpecReadLock(ss); - return SECFailure; -} - -/* -** Send some data, when using a block cipher. Package up the data with -** the length header and send it. -*/ -/* XXX assumes blocksize is > 7 */ -static PRInt32 -ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) -{ - PRUint8 *out; /* begining of output buffer. */ - PRUint8 *op; /* next output byte goes here. */ - int rv; /* value from funcs we called. */ - int count = 0; /* this function's return value. */ - - unsigned int hlen; /* output record hdr len, 2 or 3 */ - unsigned int macLen; /* MAC is this many bytes long. */ - int amount; /* of plaintext to go in record. */ - unsigned int padding; /* add this many padding byte. */ - int nout; /* ciphertext size after header. */ - unsigned int buflen; /* size of generated record. */ - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using block cipher", - SSL_GETPID(), ss->fd, len)); - PRINT_BUF(50, (ss, "clear data:", in, len)); - - while (len) { - ssl_GetSpecReadLock(ss); /*************************************/ - - macLen = ss->sec.hash->length; - /* Figure out how much to send, including mac and padding */ - amount = PR_MIN(len, MAX_BLOCK_CYPHER_LEN); - nout = amount + macLen; - padding = nout & (ss->sec.blockSize - 1); - if (padding) { - hlen = 3; - padding = ss->sec.blockSize - padding; - nout += padding; - } else { - hlen = 2; - } - buflen = hlen + nout; - if (buflen > ss->sec.writeBuf.space) { - rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen); - if (rv != SECSuccess) { - goto loser; - } - } - out = ss->sec.writeBuf.buf; - - /* Construct header */ - op = out; - if (padding) { - *op++ = MSB(nout); - *op++ = LSB(nout); - *op++ = padding; - } else { - *op++ = 0x80 | MSB(nout); - *op++ = LSB(nout); - } - - /* Calculate MAC */ - rv = ssl2_CalcMAC(op, /* MAC goes here. */ - &ss->sec, - in, amount, /* intput addr, len */ - padding); - if (rv != SECSuccess) - goto loser; - op += macLen; - - /* Copy in the input data */ - /* XXX could eliminate the copy by folding it into the encryption */ - PORT_Memcpy(op, in, amount); - op += amount; - if (padding) { - PORT_Memset(op, padding, padding); - op += padding; - } - - /* Encrypt result */ - rv = (*ss->sec.enc)(ss->sec.writecx, out + hlen, &nout, buflen - hlen, - out + hlen, op - (out + hlen)); - if (rv) - goto loser; - - ssl_ReleaseSpecReadLock(ss); /*************************************/ - - PRINT_BUF(50, (ss, "final xmit data:", out, op - out)); - - rv = ssl_DefSend(ss, out, op - out, flags & ~ssl_SEND_FLAG_MASK); - if (rv < 0) { - if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) { - rv = 0; - } else { - SSL_TRC(10, ("%d: SSL[%d]: send block error %d", - SSL_GETPID(), ss->fd, PORT_GetError())); - /* Return short write if some data already went out... */ - if (count == 0) - count = rv; - goto done; - } - } - - if (rv < (op - out)) { - /* Short write. Save the data and return. */ - if (ssl_SaveWriteData(ss, out + rv, op - out - rv) == SECFailure) { - count = SECFailure; - } else { - count += amount; - ss->sec.sendSequence++; - } - goto done; - } - - ss->sec.sendSequence++; - in += amount; - count += amount; - len -= amount; - } - -done: - return count; - -loser: - ssl_ReleaseSpecReadLock(ss); - return SECFailure; -} - -/* -** Called from: ssl2_HandleServerHelloMessage, -** ssl2_HandleClientSessionKeyMessage, -** ssl2_HandleClientHelloMessage, -** -*/ -static void -ssl2_UseEncryptedSendFunc(sslSocket *ss) -{ - ssl_GetXmitBufLock(ss); - PORT_Assert(ss->sec.hashcx != 0); - - ss->gs.encrypted = 1; - ss->sec.send = (ss->sec.blockSize > 1) ? ssl2_SendBlock : ssl2_SendStream; - ssl_ReleaseXmitBufLock(ss); -} - -/* Called while initializing socket in ssl_CreateSecurityInfo(). -** This function allows us to keep the name of ssl2_SendClear static. -*/ -void -ssl2_UseClearSendFunc(sslSocket *ss) -{ - ss->sec.send = ssl2_SendClear; -} - -/************************************************************************ -** END of Send functions. * -*************************************************************************/ - -/*********************************************************************** - * For SSL3, this gathers in and handles records/messages until either - * the handshake is complete or application data is available. - * - * For SSL2, this gathers in only the next SSLV2 record. - * - * Called from ssl_Do1stHandshake() via function pointer ss->handshake. - * Caller must hold handshake lock. - * This function acquires and releases the RecvBufLock. - * - * returns SECSuccess for success. - * returns SECWouldBlock when that value is returned by ssl2_GatherRecord() or - * ssl3_GatherCompleteHandshake(). - * returns SECFailure on all other errors. - * - * The gather functions called by ssl_GatherRecord1stHandshake are expected - * to return values interpreted as follows: - * 1 : the function completed without error. - * 0 : the function read EOF. - * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. - * -2 : the function wants ssl_GatherRecord1stHandshake to be called again - * immediately, by ssl_Do1stHandshake. - * - * This code is similar to, and easily confused with, DoRecv() in sslsecur.c - * - * This function is called from ssl_Do1stHandshake(). - * The following functions put ssl_GatherRecord1stHandshake into ss->handshake: - * ssl2_HandleMessage - * ssl2_HandleVerifyMessage - * ssl2_HandleServerHelloMessage - * ssl2_BeginClientHandshake - * ssl2_HandleClientSessionKeyMessage - * ssl3_RestartHandshakeAfterCertReq - * ssl3_RestartHandshakeAfterServerCert - * ssl2_HandleClientHelloMessage - * ssl2_BeginServerHandshake - */ -SECStatus -ssl_GatherRecord1stHandshake(sslSocket *ss) -{ - int rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetRecvBufLock(ss); - - /* The special case DTLS logic is needed here because the SSL/TLS - * version wants to auto-detect SSL2 vs. SSL3 on the initial handshake - * (ss->version == 0) but with DTLS it gets confused, so we force the - * SSL3 version. - */ - if ((ss->version >= SSL_LIBRARY_VERSION_3_0) || IS_DTLS(ss)) { - /* Wait for handshake to complete, or application data to arrive. */ - rv = ssl3_GatherCompleteHandshake(ss, 0); - } else { - /* See if we have a complete record */ - rv = ssl2_GatherRecord(ss, 0); - } - SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d", - SSL_GETPID(), ss->fd, rv)); - - ssl_ReleaseRecvBufLock(ss); - - if (rv <= 0) { - if (rv == SECWouldBlock) { - /* Progress is blocked waiting for callback completion. */ - SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)", - SSL_GETPID(), ss->fd, ss->gs.remainder)); - return SECWouldBlock; - } - if (rv == 0) { - /* EOF. Loser */ - PORT_SetError(PR_END_OF_FILE_ERROR); - } - return SECFailure; /* rv is < 0 here. */ - } - - SSL_TRC(10, ("%d: SSL[%d]: got handshake record of %d bytes", - SSL_GETPID(), ss->fd, ss->gs.recordLen)); - - ss->handshake = 0; /* makes ssl_Do1stHandshake call ss->nextHandshake.*/ - return SECSuccess; -} - -/************************************************************************/ - -/* Called from ssl2_ServerSetupSessionCypher() - * ssl2_ClientSetupSessionCypher() - */ -static SECStatus -ssl2_FillInSID(sslSessionID *sid, - int cipher, - PRUint8 *keyData, - int keyLen, - PRUint8 *ca, - int caLen, - int keyBits, - int secretKeyBits, - SSLSignType authAlgorithm, - PRUint32 authKeyBits, - SSLKEAType keaType, - PRUint32 keaKeyBits) -{ - PORT_Assert(sid->references == 1); - PORT_Assert(sid->cached == never_cached); - PORT_Assert(sid->u.ssl2.masterKey.data == 0); - PORT_Assert(sid->u.ssl2.cipherArg.data == 0); - - sid->version = SSL_LIBRARY_VERSION_2; - - sid->u.ssl2.cipherType = cipher; - sid->u.ssl2.masterKey.data = (PRUint8 *)PORT_Alloc(keyLen); - if (!sid->u.ssl2.masterKey.data) { - return SECFailure; - } - PORT_Memcpy(sid->u.ssl2.masterKey.data, keyData, keyLen); - sid->u.ssl2.masterKey.len = keyLen; - sid->u.ssl2.keyBits = keyBits; - sid->u.ssl2.secretKeyBits = secretKeyBits; - sid->authAlgorithm = authAlgorithm; - sid->authKeyBits = authKeyBits; - sid->keaType = keaType; - sid->keaKeyBits = keaKeyBits; - sid->lastAccessTime = sid->creationTime = ssl_Time(); - sid->expirationTime = sid->creationTime + ssl_sid_timeout; - - if (caLen) { - sid->u.ssl2.cipherArg.data = (PRUint8 *)PORT_Alloc(caLen); - if (!sid->u.ssl2.cipherArg.data) { - return SECFailure; - } - sid->u.ssl2.cipherArg.len = caLen; - PORT_Memcpy(sid->u.ssl2.cipherArg.data, ca, caLen); - } - return SECSuccess; -} - -/* -** Construct session keys given the masterKey (tied to the session-id), -** the client's challenge and the server's nonce. -** -** Called from ssl2_CreateSessionCypher() <- -*/ -static SECStatus -ssl2_ProduceKeys(sslSocket *ss, - SECItem *readKey, - SECItem *writeKey, - SECItem *masterKey, - PRUint8 *challenge, - PRUint8 *nonce, - int cipherType) -{ - PK11Context *cx = 0; - unsigned nkm = 0; /* number of hashes to generate key mat. */ - unsigned nkd = 0; /* size of readKey and writeKey. */ - unsigned part; - unsigned i; - unsigned off; - SECStatus rv; - PRUint8 countChar; - PRUint8 km[3 * 16]; /* buffer for key material. */ - - readKey->data = 0; - writeKey->data = 0; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - rv = SECSuccess; - cx = PK11_CreateDigestContext(SEC_OID_MD5); - if (cx == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return SECFailure; - } - - nkm = ssl_Specs[cipherType].nkm; - nkd = ssl_Specs[cipherType].nkd; - - readKey->data = (PRUint8 *)PORT_Alloc(nkd); - if (!readKey->data) - goto loser; - readKey->len = nkd; - - writeKey->data = (PRUint8 *)PORT_Alloc(nkd); - if (!writeKey->data) - goto loser; - writeKey->len = nkd; - - /* Produce key material */ - countChar = '0'; - for (i = 0, off = 0; i < nkm; i++, off += 16) { - rv = PK11_DigestBegin(cx); - rv |= PK11_DigestOp(cx, masterKey->data, masterKey->len); - rv |= PK11_DigestOp(cx, &countChar, 1); - rv |= PK11_DigestOp(cx, challenge, SSL_CHALLENGE_BYTES); - rv |= PK11_DigestOp(cx, nonce, SSL_CONNECTIONID_BYTES); - rv |= PK11_DigestFinal(cx, km + off, &part, MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } - countChar++; - } - - /* Produce keys */ - PORT_Memcpy(readKey->data, km, nkd); - PORT_Memcpy(writeKey->data, km + nkd, nkd); - -loser: - PK11_DestroyContext(cx, PR_TRUE); - return rv; -} - -/* Called from ssl2_ServerSetupSessionCypher() -** <- ssl2_HandleClientSessionKeyMessage() -** <- ssl2_HandleClientHelloMessage() -** and from ssl2_ClientSetupSessionCypher() -** <- ssl2_HandleServerHelloMessage() -*/ -static SECStatus -ssl2_CreateSessionCypher(sslSocket *ss, sslSessionID *sid, PRBool isClient) -{ - SECItem *rk = NULL; - SECItem *wk = NULL; - SECItem *param; - SECStatus rv; - int cipherType = sid->u.ssl2.cipherType; - PK11SlotInfo *slot = NULL; - CK_MECHANISM_TYPE mechanism; - SECItem readKey; - SECItem writeKey; - - void *readcx = 0; - void *writecx = 0; - readKey.data = 0; - writeKey.data = 0; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - if (ss->sec.ci.sid == 0) - goto sec_loser; /* don't crash if asserts are off */ - - /* Trying to cut down on all these switch statements that should be tables. - * So, test cipherType once, here, and then use tables below. - */ - switch (cipherType) { - case SSL_CK_RC4_128_EXPORT40_WITH_MD5: - case SSL_CK_RC4_128_WITH_MD5: - case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: - case SSL_CK_RC2_128_CBC_WITH_MD5: - case SSL_CK_DES_64_CBC_WITH_MD5: - case SSL_CK_DES_192_EDE3_CBC_WITH_MD5: - break; - - default: - SSL_DBG(("%d: SSL[%d]: ssl2_CreateSessionCypher: unknown cipher=%d", - SSL_GETPID(), ss->fd, cipherType)); - PORT_SetError(isClient ? SSL_ERROR_BAD_SERVER : SSL_ERROR_BAD_CLIENT); - goto sec_loser; - } - - rk = isClient ? &readKey : &writeKey; - wk = isClient ? &writeKey : &readKey; - - /* Produce the keys for this session */ - rv = ssl2_ProduceKeys(ss, &readKey, &writeKey, &sid->u.ssl2.masterKey, - ss->sec.ci.clientChallenge, ss->sec.ci.connectionID, - cipherType); - if (rv != SECSuccess) - goto loser; - PRINT_BUF(7, (ss, "Session read-key: ", rk->data, rk->len)); - PRINT_BUF(7, (ss, "Session write-key: ", wk->data, wk->len)); - - PORT_Memcpy(ss->sec.ci.readKey, readKey.data, readKey.len); - PORT_Memcpy(ss->sec.ci.writeKey, writeKey.data, writeKey.len); - ss->sec.ci.keySize = readKey.len; - - /* Setup the MAC */ - rv = ssl2_CreateMAC(&ss->sec, rk, wk, cipherType); - if (rv != SECSuccess) - goto loser; - - /* First create the session key object */ - SSL_TRC(3, ("%d: SSL[%d]: using %s", SSL_GETPID(), ss->fd, - ssl_cipherName[cipherType])); - - mechanism = ssl_Specs[cipherType].mechanism; - - /* set destructer before we call loser... */ - ss->sec.destroy = (void (*)(void *, PRBool))PK11_DestroyContext; - slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg); - if (slot == NULL) - goto loser; - - param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg); - if (param == NULL) - goto loser; - readcx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap, - CKA_DECRYPT, rk, param, - ss->pkcs11PinArg); - SECITEM_FreeItem(param, PR_TRUE); - if (readcx == NULL) - goto loser; - - /* build the client context */ - param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg); - if (param == NULL) - goto loser; - writecx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap, - CKA_ENCRYPT, wk, param, - ss->pkcs11PinArg); - SECITEM_FreeItem(param, PR_TRUE); - if (writecx == NULL) - goto loser; - PK11_FreeSlot(slot); - - rv = SECSuccess; - ss->sec.enc = (SSLCipher)PK11_CipherOp; - ss->sec.dec = (SSLCipher)PK11_CipherOp; - ss->sec.readcx = (void *)readcx; - ss->sec.writecx = (void *)writecx; - ss->sec.blockSize = ssl_Specs[cipherType].blockSize; - ss->sec.blockShift = ssl_Specs[cipherType].blockShift; - ss->sec.cipherType = sid->u.ssl2.cipherType; - ss->sec.keyBits = sid->u.ssl2.keyBits; - ss->sec.secretKeyBits = sid->u.ssl2.secretKeyBits; - goto done; - -loser: - if (ss->sec.destroy) { - if (readcx) - (*ss->sec.destroy)(readcx, PR_TRUE); - if (writecx) - (*ss->sec.destroy)(writecx, PR_TRUE); - } - ss->sec.destroy = NULL; - if (slot) - PK11_FreeSlot(slot); - -sec_loser: - rv = SECFailure; - -done: - if (rk) { - SECITEM_ZfreeItem(rk, PR_FALSE); - } - if (wk) { - SECITEM_ZfreeItem(wk, PR_FALSE); - } - return rv; -} - -/* -** Setup the server ciphers given information from a CLIENT-MASTER-KEY -** message. -** "ss" pointer to the ssl-socket object -** "cipher" the cipher type to use -** "keyBits" the size of the final cipher key -** "ck" the clear-key data -** "ckLen" the number of bytes of clear-key data -** "ek" the encrypted-key data -** "ekLen" the number of bytes of encrypted-key data -** "ca" the cipher-arg data -** "caLen" the number of bytes of cipher-arg data -** -** The MASTER-KEY is constructed by first decrypting the encrypted-key -** data. This produces the SECRET-KEY-DATA. The MASTER-KEY is composed by -** concatenating the clear-key data with the SECRET-KEY-DATA. This code -** checks to make sure that the client didn't send us an improper amount -** of SECRET-KEY-DATA (it restricts the length of that data to match the -** spec). -** -** Called from ssl2_HandleClientSessionKeyMessage(). -*/ -static SECStatus -ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits, - PRUint8 *ck, unsigned int ckLen, - PRUint8 *ek, unsigned int ekLen, - PRUint8 *ca, unsigned int caLen) -{ - PRUint8 *dk = NULL; /* decrypted master key */ - sslSessionID *sid; - sslServerCerts *sc = ss->serverCerts + kt_rsa; - PRUint8 *kbuf = 0; /* buffer for RSA decrypted data. */ - unsigned int ddLen; /* length of RSA decrypted data in kbuf */ - unsigned int keySize; - unsigned int dkLen; /* decrypted key length in bytes */ - int modulusLen; - SECStatus rv; - PRUint16 allowed; /* cipher kinds enabled and allowed by policy */ - PRUint8 mkbuf[SSL_MAX_MASTER_KEY_BYTES]; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert((sc->SERVERKEY != 0)); - PORT_Assert((ss->sec.ci.sid != 0)); - sid = ss->sec.ci.sid; - - /* Trying to cut down on all these switch statements that should be tables. - * So, test cipherType once, here, and then use tables below. - */ - switch (cipher) { - case SSL_CK_RC4_128_EXPORT40_WITH_MD5: - case SSL_CK_RC4_128_WITH_MD5: - case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: - case SSL_CK_RC2_128_CBC_WITH_MD5: - case SSL_CK_DES_64_CBC_WITH_MD5: - case SSL_CK_DES_192_EDE3_CBC_WITH_MD5: - break; - - default: - SSL_DBG(("%d: SSL[%d]: ssl2_ServerSetupSessionCypher: unknown cipher=%d", - SSL_GETPID(), ss->fd, cipher)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto loser; - } - - allowed = ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED; - if (!(allowed & (1 << cipher))) { - /* client chose a kind we don't allow! */ - SSL_DBG(("%d: SSL[%d]: disallowed cipher=%d", - SSL_GETPID(), ss->fd, cipher)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto loser; - } - - keySize = ssl_Specs[cipher].keyLen; - if (keyBits != keySize * BPB) { - SSL_DBG(("%d: SSL[%d]: invalid master secret key length=%d (bits)!", - SSL_GETPID(), ss->fd, keyBits)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto loser; - } - - if (ckLen != ssl_Specs[cipher].pubLen) { - SSL_DBG(("%d: SSL[%d]: invalid clear key length, ckLen=%d (bytes)!", - SSL_GETPID(), ss->fd, ckLen)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto loser; - } - - if (caLen != ssl_Specs[cipher].ivLen) { - SSL_DBG(("%d: SSL[%d]: invalid key args length, caLen=%d (bytes)!", - SSL_GETPID(), ss->fd, caLen)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto loser; - } - - modulusLen = PK11_GetPrivateModulusLen(sc->SERVERKEY); - if (modulusLen < 0) { - /* XXX If the key is bad, then PK11_PubDecryptRaw will fail below. */ - modulusLen = ekLen; - } - if (ekLen > (unsigned int)modulusLen || ekLen + ckLen < keySize) { - SSL_DBG(("%d: SSL[%d]: invalid encrypted key length, ekLen=%d (bytes)!", - SSL_GETPID(), ss->fd, ekLen)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto loser; - } - - /* allocate the buffer to hold the decrypted portion of the key. */ - kbuf = (PRUint8 *)PORT_Alloc(modulusLen); - if (!kbuf) { - goto loser; - } - dkLen = keySize - ckLen; - dk = kbuf + modulusLen - dkLen; - - /* Decrypt encrypted half of the key. - ** NOTE: PK11_PubDecryptRaw will barf on a non-RSA key. This is - ** desired behavior here. - */ - rv = PK11_PubDecryptRaw(sc->SERVERKEY, kbuf, &ddLen, modulusLen, ek, ekLen); - if (rv != SECSuccess) - goto hide_loser; - - /* Is the length of the decrypted data (ddLen) the expected value? */ - if (modulusLen != ddLen) - goto hide_loser; - - /* Cheaply verify that PKCS#1 was used to format the encryption block */ - if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (dk[-1] != 0x00)) { - SSL_DBG(("%d: SSL[%d]: strange encryption block", - SSL_GETPID(), ss->fd)); - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto hide_loser; - } - - /* Make sure we're not subject to a version rollback attack. */ - if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - static const PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03 }; - - if (PORT_Memcmp(dk - 8 - 1, threes, 8) == 0) { - PORT_SetError(SSL_ERROR_BAD_CLIENT); - goto hide_loser; - } - } - if (0) { - hide_loser: - /* Defense against the Bleichenbacher attack. - * Provide the client with NO CLUES that the decrypted master key - * was erroneous. Don't send any error messages. - * Instead, Generate a completely bogus master key . - */ - PK11_GenerateRandom(dk, dkLen); - } - - /* - ** Construct master key out of the pieces. - */ - if (ckLen) { - PORT_Memcpy(mkbuf, ck, ckLen); - } - PORT_Memcpy(mkbuf + ckLen, dk, dkLen); - - /* Fill in session-id */ - rv = ssl2_FillInSID(sid, cipher, mkbuf, keySize, ca, caLen, - keyBits, keyBits - (ckLen << 3), - ss->sec.authAlgorithm, ss->sec.authKeyBits, - ss->sec.keaType, ss->sec.keaKeyBits); - if (rv != SECSuccess) { - goto loser; - } - - /* Create session ciphers */ - rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE); - if (rv != SECSuccess) { - goto loser; - } - - SSL_TRC(1, ("%d: SSL[%d]: server, using %s cipher, clear=%d total=%d", - SSL_GETPID(), ss->fd, ssl_cipherName[cipher], - ckLen << 3, keySize << 3)); - rv = SECSuccess; - goto done; - -loser: - rv = SECFailure; - -done: - PORT_Free(kbuf); - return rv; -} - -/************************************************************************/ - -/* -** Rewrite the incoming cipher specs, comparing to list of specs we support, -** (ss->cipherSpecs) and eliminating anything we don't support -** -* Note: Our list may contain SSL v3 ciphers. -* We MUST NOT match on any of those. -* Fortunately, this is easy to detect because SSLv3 ciphers have zero -* in the first byte, and none of the SSLv2 ciphers do. -* -* Called from ssl2_HandleClientHelloMessage(). -* Returns the number of bytes of "qualified cipher specs", -* which is typically a multiple of 3, but will be zero if there are none. -*/ -static int -ssl2_QualifyCypherSpecs(sslSocket *ss, - PRUint8 *cs, /* cipher specs in client hello msg. */ - int csLen) -{ - PRUint8 *ms; - PRUint8 *hs; - PRUint8 *qs; - int mc; - int hc; - PRUint8 qualifiedSpecs[ssl2_NUM_SUITES_IMPLEMENTED * 3]; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - if (!ss->cipherSpecs) { - SECStatus rv = ssl2_ConstructCipherSpecs(ss); - if (rv != SECSuccess || !ss->cipherSpecs) - return 0; - } - - PRINT_BUF(10, (ss, "specs from client:", cs, csLen)); - qs = qualifiedSpecs; - ms = ss->cipherSpecs; - for (mc = ss->sizeCipherSpecs; mc > 0; mc -= 3, ms += 3) { - if (ms[0] == 0) - continue; - for (hs = cs, hc = csLen; hc > 0; hs += 3, hc -= 3) { - if ((hs[0] == ms[0]) && - (hs[1] == ms[1]) && - (hs[2] == ms[2])) { - /* Copy this cipher spec into the "keep" section */ - qs[0] = hs[0]; - qs[1] = hs[1]; - qs[2] = hs[2]; - qs += 3; - break; - } - } - } - hc = qs - qualifiedSpecs; - PRINT_BUF(10, (ss, "qualified specs from client:", qualifiedSpecs, hc)); - PORT_Memcpy(cs, qualifiedSpecs, hc); - return hc; -} - -/* -** Pick the best cipher we can find, given the array of server cipher -** specs. Returns cipher number (e.g. SSL_CK_*), or -1 for no overlap. -** If successful, stores the master key size (bytes) in *pKeyLen. -** -** This is correct only for the client side, but presently -** this function is only called from -** ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage() -** -** Note that most servers only return a single cipher suite in their -** ServerHello messages. So, the code below for finding the "best" cipher -** suite usually has only one choice. The client and server should send -** their cipher suite lists sorted in descending order by preference. -*/ -static int -ssl2_ChooseSessionCypher(sslSocket *ss, - int hc, /* number of cs's in hs. */ - PRUint8 *hs, /* server hello's cipher suites. */ - int *pKeyLen) /* out: sym key size in bytes. */ -{ - PRUint8 *ms; - unsigned int i; - int bestKeySize; - int bestRealKeySize; - int bestCypher; - int keySize; - int realKeySize; - PRUint8 *ohs = hs; - const PRUint8 *preferred; - static const PRUint8 noneSuch[3] = { 0, 0, 0 }; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - if (!ss->cipherSpecs) { - SECStatus rv = ssl2_ConstructCipherSpecs(ss); - if (rv != SECSuccess || !ss->cipherSpecs) - goto loser; - } - - if (!ss->preferredCipher) { - unsigned int allowed = ss->allowedByPolicy & ss->chosenPreference & - SSL_CB_IMPLEMENTED; - if (allowed) { - preferred = implementedCipherSuites; - for (i = ssl2_NUM_SUITES_IMPLEMENTED; i > 0; --i) { - if (0 != (allowed & (1U << preferred[0]))) { - ss->preferredCipher = preferred; - break; - } - preferred += 3; - } - } - } - preferred = ss->preferredCipher ? ss->preferredCipher : noneSuch; - /* - ** Scan list of ciphers received from peer and look for a match in - ** our list. - * Note: Our list may contain SSL v3 ciphers. - * We MUST NOT match on any of those. - * Fortunately, this is easy to detect because SSLv3 ciphers have zero - * in the first byte, and none of the SSLv2 ciphers do. - */ - bestKeySize = bestRealKeySize = 0; - bestCypher = -1; - while (--hc >= 0) { - for (i = 0, ms = ss->cipherSpecs; i < ss->sizeCipherSpecs; i += 3, ms += 3) { - if ((hs[0] == preferred[0]) && - (hs[1] == preferred[1]) && - (hs[2] == preferred[2]) && - hs[0] != 0) { - /* Pick this cipher immediately! */ - *pKeyLen = (((hs[1] << 8) | hs[2]) + 7) >> 3; - return hs[0]; - } - if ((hs[0] == ms[0]) && (hs[1] == ms[1]) && (hs[2] == ms[2]) && - hs[0] != 0) { - /* Found a match */ - - /* Use secret keySize to determine which cipher is best */ - realKeySize = (hs[1] << 8) | hs[2]; - switch (hs[0]) { - case SSL_CK_RC4_128_EXPORT40_WITH_MD5: - case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: - keySize = 40; - break; - default: - keySize = realKeySize; - break; - } - if (keySize > bestKeySize) { - bestCypher = hs[0]; - bestKeySize = keySize; - bestRealKeySize = realKeySize; - } - } - } - hs += 3; - } - if (bestCypher < 0) { - /* - ** No overlap between server and client. Re-examine server list - ** to see what kind of ciphers it does support so that we can set - ** the error code appropriately. - */ - if ((ohs[0] == SSL_CK_RC4_128_WITH_MD5) || - (ohs[0] == SSL_CK_RC2_128_CBC_WITH_MD5)) { - PORT_SetError(SSL_ERROR_US_ONLY_SERVER); - } else if ((ohs[0] == SSL_CK_RC4_128_EXPORT40_WITH_MD5) || - (ohs[0] == SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)) { - PORT_SetError(SSL_ERROR_EXPORT_ONLY_SERVER); - } else { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - } - SSL_DBG(("%d: SSL[%d]: no cipher overlap", SSL_GETPID(), ss->fd)); - goto loser; - } - *pKeyLen = (bestRealKeySize + 7) >> 3; - return bestCypher; - -loser: - return -1; -} - -static SECStatus -ssl2_ClientHandleServerCert(sslSocket *ss, PRUint8 *certData, int certLen) -{ - CERTCertificate *cert = NULL; - SECItem certItem; - - certItem.data = certData; - certItem.len = certLen; - - /* decode the certificate */ - cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL, - PR_FALSE, PR_TRUE); - - if (cert == NULL) { - SSL_DBG(("%d: SSL[%d]: decode of server certificate fails", - SSL_GETPID(), ss->fd)); - PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); - return SECFailure; - } - -#ifdef TRACE - { - if (ssl_trace >= 1) { - char *issuer; - char *subject; - issuer = CERT_NameToAscii(&cert->issuer); - subject = CERT_NameToAscii(&cert->subject); - SSL_TRC(1, ("%d: server certificate issuer: '%s'", - SSL_GETPID(), issuer ? issuer : "OOPS")); - SSL_TRC(1, ("%d: server name: '%s'", - SSL_GETPID(), subject ? subject : "OOPS")); - PORT_Free(issuer); - PORT_Free(subject); - } - } -#endif - - ss->sec.peerCert = cert; - return SECSuccess; -} - -/* - * Format one block of data for public/private key encryption using - * the rules defined in PKCS #1. SSL2 does this itself to handle the - * rollback detection. - */ -#define RSA_BLOCK_MIN_PAD_LEN 8 -#define RSA_BLOCK_FIRST_OCTET 0x00 -#define RSA_BLOCK_AFTER_PAD_OCTET 0x00 -#define RSA_BLOCK_PUBLIC_OCTET 0x02 -unsigned char * -ssl_FormatSSL2Block(unsigned modulusLen, SECItem *data) -{ - unsigned char *block; - unsigned char *bp; - int padLen; - SECStatus rv; - int i; - - if (modulusLen < data->len + (3 + RSA_BLOCK_MIN_PAD_LEN)) { - PORT_SetError(SEC_ERROR_BAD_KEY); - return NULL; - } - block = (unsigned char *)PORT_Alloc(modulusLen); - if (block == NULL) - return NULL; - - bp = block; - - /* - * All RSA blocks start with two octets: - * 0x00 || BlockType - */ - *bp++ = RSA_BLOCK_FIRST_OCTET; - *bp++ = RSA_BLOCK_PUBLIC_OCTET; - - /* - * 0x00 || BT || Pad || 0x00 || ActualData - * 1 1 padLen 1 data->len - * Pad is all non-zero random bytes. - */ - padLen = modulusLen - data->len - 3; - PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN); - rv = PK11_GenerateRandom(bp, padLen); - if (rv == SECFailure) - goto loser; - /* replace all the 'zero' bytes */ - for (i = 0; i < padLen; i++) { - while (bp[i] == RSA_BLOCK_AFTER_PAD_OCTET) { - rv = PK11_GenerateRandom(bp + i, 1); - if (rv == SECFailure) - goto loser; - } - } - bp += padLen; - *bp++ = RSA_BLOCK_AFTER_PAD_OCTET; - PORT_Memcpy(bp, data->data, data->len); - - return block; -loser: - if (block) - PORT_Free(block); - return NULL; -} - -/* -** Given the server's public key and cipher specs, generate a session key -** that is ready to use for encrypting/decrypting the byte stream. At -** the same time, generate the SSL_MT_CLIENT_MASTER_KEY message and -** send it to the server. -** -** Called from ssl2_HandleServerHelloMessage() -*/ -static SECStatus -ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen) -{ - sslSessionID *sid; - PRUint8 *ca; /* points to iv data, or NULL if none. */ - PRUint8 *ekbuf = 0; - CERTCertificate *cert = 0; - SECKEYPublicKey *serverKey = 0; - unsigned modulusLen = 0; - SECStatus rv; - int cipher; - int keyLen; /* cipher symkey size in bytes. */ - int ckLen; /* publicly reveal this many bytes of key. */ - int caLen; /* length of IV data at *ca. */ - int nc; - - unsigned char *eblock; /* holds unencrypted PKCS#1 formatted key. */ - SECItem rek; /* holds portion of symkey to be encrypted. */ - - PRUint8 keyData[SSL_MAX_MASTER_KEY_BYTES]; - PRUint8 iv[8]; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - eblock = NULL; - - sid = ss->sec.ci.sid; - PORT_Assert(sid != 0); - - cert = ss->sec.peerCert; - - serverKey = CERT_ExtractPublicKey(cert); - if (!serverKey) { - SSL_DBG(("%d: SSL[%d]: extract public key failed: error=%d", - SSL_GETPID(), ss->fd, PORT_GetError())); - PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); - rv = SECFailure; - goto loser2; - } - - ss->sec.authAlgorithm = ssl_sign_rsa; - ss->sec.keaType = ssl_kea_rsa; - ss->sec.keaKeyBits = - ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey); - - /* Choose a compatible cipher with the server */ - nc = csLen / 3; - cipher = ssl2_ChooseSessionCypher(ss, nc, cs, &keyLen); - if (cipher < 0) { - /* ssl2_ChooseSessionCypher has set error code. */ - ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS); - goto loser; - } - - /* Generate the random keys */ - PK11_GenerateRandom(keyData, sizeof(keyData)); - - /* - ** Next, carve up the keys into clear and encrypted portions. The - ** clear data is taken from the start of keyData and the encrypted - ** portion from the remainder. Note that each of these portions is - ** carved in half, one half for the read-key and one for the - ** write-key. - */ - ca = 0; - - /* We know that cipher is a legit value here, because - * ssl2_ChooseSessionCypher doesn't return bogus values. - */ - ckLen = ssl_Specs[cipher].pubLen; /* cleartext key length. */ - caLen = ssl_Specs[cipher].ivLen; /* IV length. */ - if (caLen) { - PORT_Assert(sizeof iv >= caLen); - PK11_GenerateRandom(iv, caLen); - ca = iv; - } - - /* Fill in session-id */ - rv = ssl2_FillInSID(sid, cipher, keyData, keyLen, - ca, caLen, keyLen << 3, (keyLen - ckLen) << 3, - ss->sec.authAlgorithm, ss->sec.authKeyBits, - ss->sec.keaType, ss->sec.keaKeyBits); - if (rv != SECSuccess) { - goto loser; - } - - SSL_TRC(1, ("%d: SSL[%d]: client, using %s cipher, clear=%d total=%d", - SSL_GETPID(), ss->fd, ssl_cipherName[cipher], - ckLen << 3, keyLen << 3)); - - /* Now setup read and write ciphers */ - rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE); - if (rv != SECSuccess) { - goto loser; - } - - /* - ** Fill in the encryption buffer with some random bytes. Then - ** copy in the portion of the session key we are encrypting. - */ - modulusLen = SECKEY_PublicKeyStrength(serverKey); - rek.data = keyData + ckLen; - rek.len = keyLen - ckLen; - eblock = ssl_FormatSSL2Block(modulusLen, &rek); - if (eblock == NULL) - goto loser; - - /* Set up the padding for version 2 rollback detection. */ - /* XXX We should really use defines here */ - if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - PORT_Assert((modulusLen - rek.len) > 12); - PORT_Memset(eblock + modulusLen - rek.len - 8 - 1, 0x03, 8); - } - ekbuf = (PRUint8 *)PORT_Alloc(modulusLen); - if (!ekbuf) - goto loser; - PRINT_BUF(10, (ss, "master key encryption block:", - eblock, modulusLen)); - - /* Encrypt ekitem */ - rv = PK11_PubEncryptRaw(serverKey, ekbuf, eblock, modulusLen, - ss->pkcs11PinArg); - if (rv) - goto loser; - - /* Now we have everything ready to send */ - rv = ssl2_SendSessionKeyMessage(ss, cipher, keyLen << 3, ca, caLen, - keyData, ckLen, ekbuf, modulusLen); - if (rv != SECSuccess) { - goto loser; - } - rv = SECSuccess; - goto done; - -loser: - rv = SECFailure; - -loser2: -done: - PORT_Memset(keyData, 0, sizeof(keyData)); - PORT_ZFree(ekbuf, modulusLen); - PORT_ZFree(eblock, modulusLen); - SECKEY_DestroyPublicKey(serverKey); - return rv; -} - -/************************************************************************/ - -/* - * Called from ssl2_HandleMessage in response to SSL_MT_SERVER_FINISHED message. - * Caller holds recvBufLock and handshakeLock - */ -static void -ssl2_ClientRegSessionID(sslSocket *ss, PRUint8 *s) -{ - sslSessionID *sid = ss->sec.ci.sid; - - /* Record entry in nonce cache */ - if (sid->peerCert == NULL) { - PORT_Memcpy(sid->u.ssl2.sessionID, s, sizeof(sid->u.ssl2.sessionID)); - sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); - } - if (!ss->opt.noCache && sid->cached == never_cached) - (*ss->sec.cache)(sid); -} - -/* Called from ssl2_HandleMessage() */ -static SECStatus -ssl2_TriggerNextMessage(sslSocket *ss) -{ - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - if ((ss->sec.ci.requiredElements & CIS_HAVE_CERTIFICATE) && - !(ss->sec.ci.sentElements & CIS_HAVE_CERTIFICATE)) { - ss->sec.ci.sentElements |= CIS_HAVE_CERTIFICATE; - rv = ssl2_SendCertificateRequestMessage(ss); - return rv; - } - return SECSuccess; -} - -/* See if it's time to send our finished message, or if the handshakes are -** complete. Send finished message if appropriate. -** Returns SECSuccess unless anything goes wrong. -** -** Called from ssl2_HandleMessage, -** ssl2_HandleVerifyMessage -** ssl2_HandleServerHelloMessage -** ssl2_HandleClientSessionKeyMessage -*/ -static SECStatus -ssl2_TryToFinish(sslSocket *ss) -{ - SECStatus rv; - char e, ef; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - e = ss->sec.ci.elements; - ef = e | CIS_HAVE_FINISHED; - if ((ef & ss->sec.ci.requiredElements) == ss->sec.ci.requiredElements) { - if (ss->sec.isServer) { - /* Send server finished message if we already didn't */ - rv = ssl2_SendServerFinishedMessage(ss); - } else { - /* Send client finished message if we already didn't */ - rv = ssl2_SendClientFinishedMessage(ss); - } - if (rv != SECSuccess) { - return rv; - } - if ((e & ss->sec.ci.requiredElements) == ss->sec.ci.requiredElements) { - /* Totally finished */ - ss->handshake = 0; - return SECSuccess; - } - } - return SECSuccess; -} - -/* -** Called from ssl2_HandleRequestCertificate -*/ -static SECStatus -ssl2_SignResponse(sslSocket *ss, - SECKEYPrivateKey *key, - SECItem *response) -{ - SGNContext *sgn = NULL; - PRUint8 *challenge; - unsigned int len; - SECStatus rv = SECFailure; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - challenge = ss->sec.ci.serverChallenge; - len = ss->sec.ci.serverChallengeLen; - - /* Sign the expected data... */ - sgn = SGN_NewContext(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, key); - if (!sgn) - goto done; - rv = SGN_Begin(sgn); - if (rv != SECSuccess) - goto done; - rv = SGN_Update(sgn, ss->sec.ci.readKey, ss->sec.ci.keySize); - if (rv != SECSuccess) - goto done; - rv = SGN_Update(sgn, ss->sec.ci.writeKey, ss->sec.ci.keySize); - if (rv != SECSuccess) - goto done; - rv = SGN_Update(sgn, challenge, len); - if (rv != SECSuccess) - goto done; - rv = SGN_Update(sgn, ss->sec.peerCert->derCert.data, - ss->sec.peerCert->derCert.len); - if (rv != SECSuccess) - goto done; - rv = SGN_End(sgn, response); - if (rv != SECSuccess) - goto done; - -done: - SGN_DestroyContext(sgn, PR_TRUE); - return rv == SECSuccess ? SECSuccess : SECFailure; -} - -/* -** Try to handle a request-certificate message. Get client's certificate -** and private key and sign a message for the server to see. -** Caller must hold handshakeLock -** -** Called from ssl2_HandleMessage(). -*/ -static int -ssl2_HandleRequestCertificate(sslSocket *ss) -{ - CERTCertificate *cert = NULL; /* app-selected client cert. */ - SECKEYPrivateKey *key = NULL; /* priv key for cert. */ - SECStatus rv; - SECItem response; - int ret = 0; - PRUint8 authType; - - /* - * These things all need to be initialized before we can "goto loser". - */ - response.data = NULL; - - /* get challenge info from connectionInfo */ - authType = ss->sec.ci.authType; - - if (authType != SSL_AT_MD5_WITH_RSA_ENCRYPTION) { - SSL_TRC(7, ("%d: SSL[%d]: unsupported auth type 0x%x", SSL_GETPID(), - ss->fd, authType)); - goto no_cert_error; - } - - /* Get certificate and private-key from client */ - if (!ss->getClientAuthData) { - SSL_TRC(7, ("%d: SSL[%d]: client doesn't support client-auth", - SSL_GETPID(), ss->fd)); - goto no_cert_error; - } - ret = (*ss->getClientAuthData)(ss->getClientAuthDataArg, ss->fd, - NULL, &cert, &key); - if (ret == SECWouldBlock) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - ret = -1; - goto loser; - } - - if (ret) { - goto no_cert_error; - } - - /* check what the callback function returned */ - if ((!cert) || (!key)) { - /* we are missing either the key or cert */ - if (cert) { - /* got a cert, but no key - free it */ - CERT_DestroyCertificate(cert); - cert = NULL; - } - if (key) { - /* got a key, but no cert - free it */ - SECKEY_DestroyPrivateKey(key); - key = NULL; - } - goto no_cert_error; - } - - rv = ssl2_SignResponse(ss, key, &response); - if (rv != SECSuccess) { - ret = -1; - goto loser; - } - - /* Send response message */ - ret = ssl2_SendCertificateResponseMessage(ss, &cert->derCert, &response); - - /* Now, remember the cert we sent. But first, forget any previous one. */ - if (ss->sec.localCert) { - CERT_DestroyCertificate(ss->sec.localCert); - } - ss->sec.localCert = CERT_DupCertificate(cert); - PORT_Assert(!ss->sec.ci.sid->localCert); - if (ss->sec.ci.sid->localCert) { - CERT_DestroyCertificate(ss->sec.ci.sid->localCert); - } - ss->sec.ci.sid->localCert = cert; - cert = NULL; - - goto done; - -no_cert_error: - SSL_TRC(7, ("%d: SSL[%d]: no certificate (ret=%d)", SSL_GETPID(), - ss->fd, ret)); - ret = ssl2_SendErrorMessage(ss, SSL_PE_NO_CERTIFICATE); - -loser: -done: - if (cert) { - CERT_DestroyCertificate(cert); - } - if (key) { - SECKEY_DestroyPrivateKey(key); - } - if (response.data) { - PORT_Free(response.data); - } - - return ret; -} - -/* -** Called from ssl2_HandleMessage for SSL_MT_CLIENT_CERTIFICATE message. -** Caller must hold HandshakeLock and RecvBufLock, since cd and response -** are contained in the gathered input data. -*/ -static SECStatus -ssl2_HandleClientCertificate(sslSocket *ss, - PRUint8 certType, /* XXX unused */ - PRUint8 *cd, - unsigned int cdLen, - PRUint8 *response, - unsigned int responseLen) -{ - CERTCertificate *cert = NULL; - SECKEYPublicKey *pubKey = NULL; - VFYContext *vfy = NULL; - SECItem *derCert; - SECStatus rv = SECFailure; - SECItem certItem; - SECItem rep; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - /* Extract the certificate */ - certItem.data = cd; - certItem.len = cdLen; - - cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL, - PR_FALSE, PR_TRUE); - if (cert == NULL) { - goto loser; - } - - /* save the certificate, since the auth routine will need it */ - ss->sec.peerCert = cert; - - /* Extract the public key */ - pubKey = CERT_ExtractPublicKey(cert); - if (!pubKey) - goto loser; - - /* Verify the response data... */ - rep.data = response; - rep.len = responseLen; - /* SSL 2.0 only supports RSA certs, so we don't have to worry about - * DSA here. */ - vfy = VFY_CreateContext(pubKey, &rep, SEC_OID_PKCS1_RSA_ENCRYPTION, - ss->pkcs11PinArg); - if (!vfy) - goto loser; - rv = VFY_Begin(vfy); - if (rv) - goto loser; - - rv = VFY_Update(vfy, ss->sec.ci.readKey, ss->sec.ci.keySize); - if (rv) - goto loser; - rv = VFY_Update(vfy, ss->sec.ci.writeKey, ss->sec.ci.keySize); - if (rv) - goto loser; - rv = VFY_Update(vfy, ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES); - if (rv) - goto loser; - - derCert = &ss->serverCerts[kt_rsa].serverCert->derCert; - rv = VFY_Update(vfy, derCert->data, derCert->len); - if (rv) - goto loser; - rv = VFY_End(vfy); - if (rv) - goto loser; - - /* Now ask the server application if it likes the certificate... */ - rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, - ss->fd, PR_TRUE, PR_TRUE); - /* Hey, it liked it. */ - if (SECSuccess == rv) - goto done; - -loser: - ss->sec.peerCert = NULL; - CERT_DestroyCertificate(cert); - -done: - VFY_DestroyContext(vfy, PR_TRUE); - SECKEY_DestroyPublicKey(pubKey); - return rv; -} - -/* -** Handle remaining messages between client/server. Process finished -** messages from either side and any authentication requests. -** This should only be called for SSLv2 handshake messages, -** not for application data records. -** Caller must hold handshake lock. -** -** Called from ssl_Do1stHandshake(). -** -*/ -static SECStatus -ssl2_HandleMessage(sslSocket *ss) -{ - PRUint8 *data; - PRUint8 *cid; - unsigned len, certType, certLen, responseLen; - int rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ssl_GetRecvBufLock(ss); - - data = ss->gs.buf.buf + ss->gs.recordOffset; - - if (ss->gs.recordLen < 1) { - goto bad_peer; - } - SSL_TRC(3, ("%d: SSL[%d]: received %d message", - SSL_GETPID(), ss->fd, data[0])); - DUMP_MSG(29, (ss, data, ss->gs.recordLen)); - - switch (data[0]) { - case SSL_MT_CLIENT_FINISHED: - if (ss->sec.ci.elements & CIS_HAVE_FINISHED) { - SSL_DBG(("%d: SSL[%d]: dup client-finished message", - SSL_GETPID(), ss->fd)); - goto bad_peer; - } - - /* See if nonce matches */ - len = ss->gs.recordLen - 1; - cid = data + 1; - if ((len != sizeof(ss->sec.ci.connectionID)) || - (PORT_Memcmp(ss->sec.ci.connectionID, cid, len) != 0)) { - SSL_DBG(("%d: SSL[%d]: bad connection-id", SSL_GETPID(), ss->fd)); - PRINT_BUF(5, (ss, "sent connection-id", - ss->sec.ci.connectionID, - sizeof(ss->sec.ci.connectionID))); - PRINT_BUF(5, (ss, "rcvd connection-id", cid, len)); - goto bad_peer; - } - - SSL_TRC(5, ("%d: SSL[%d]: got client finished, waiting for 0x%d", - SSL_GETPID(), ss->fd, - ss->sec.ci.requiredElements ^ ss->sec.ci.elements)); - ss->sec.ci.elements |= CIS_HAVE_FINISHED; - break; - - case SSL_MT_SERVER_FINISHED: - if (ss->sec.ci.elements & CIS_HAVE_FINISHED) { - SSL_DBG(("%d: SSL[%d]: dup server-finished message", - SSL_GETPID(), ss->fd)); - goto bad_peer; - } - - if (ss->gs.recordLen - 1 != SSL2_SESSIONID_BYTES) { - SSL_DBG(("%d: SSL[%d]: bad server-finished message, len=%d", - SSL_GETPID(), ss->fd, ss->gs.recordLen)); - goto bad_peer; - } - ssl2_ClientRegSessionID(ss, data + 1); - SSL_TRC(5, ("%d: SSL[%d]: got server finished, waiting for 0x%d", - SSL_GETPID(), ss->fd, - ss->sec.ci.requiredElements ^ ss->sec.ci.elements)); - ss->sec.ci.elements |= CIS_HAVE_FINISHED; - break; - - case SSL_MT_REQUEST_CERTIFICATE: - len = ss->gs.recordLen - 2; - if ((len < SSL_MIN_CHALLENGE_BYTES) || - (len > SSL_MAX_CHALLENGE_BYTES)) { - /* Bad challenge */ - SSL_DBG(("%d: SSL[%d]: bad cert request message: code len=%d", - SSL_GETPID(), ss->fd, len)); - goto bad_peer; - } - - /* save auth request info */ - ss->sec.ci.authType = data[1]; - ss->sec.ci.serverChallengeLen = len; - PORT_Memcpy(ss->sec.ci.serverChallenge, data + 2, len); - - rv = ssl2_HandleRequestCertificate(ss); - if (rv == SECWouldBlock) { - SSL_TRC(3, ("%d: SSL[%d]: async cert request", - SSL_GETPID(), ss->fd)); - /* someone is handling this asynchronously */ - ssl_ReleaseRecvBufLock(ss); - return SECWouldBlock; - } - if (rv) { - SET_ERROR_CODE - goto loser; - } - break; - - case SSL_MT_CLIENT_CERTIFICATE: - if (!ss->authCertificate) { - /* Server asked for authentication and can't handle it */ - PORT_SetError(SSL_ERROR_BAD_SERVER); - goto loser; - } - if (ss->gs.recordLen < SSL_HL_CLIENT_CERTIFICATE_HBYTES) { - SET_ERROR_CODE - goto loser; - } - certType = data[1]; - certLen = (data[2] << 8) | data[3]; - responseLen = (data[4] << 8) | data[5]; - if (certType != SSL_CT_X509_CERTIFICATE) { - PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); - goto loser; - } - if (certLen + responseLen + SSL_HL_CLIENT_CERTIFICATE_HBYTES > - ss->gs.recordLen) { - /* prevent overflow crash. */ - rv = SECFailure; - } else - rv = ssl2_HandleClientCertificate(ss, data[1], - data + SSL_HL_CLIENT_CERTIFICATE_HBYTES, - certLen, - data + SSL_HL_CLIENT_CERTIFICATE_HBYTES + certLen, - responseLen); - if (rv) { - (void)ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE); - SET_ERROR_CODE - goto loser; - } - ss->sec.ci.elements |= CIS_HAVE_CERTIFICATE; - break; - - case SSL_MT_ERROR: - rv = (data[1] << 8) | data[2]; - SSL_TRC(2, ("%d: SSL[%d]: got error message, error=0x%x", - SSL_GETPID(), ss->fd, rv)); - - /* Convert protocol error number into API error number */ - switch (rv) { - case SSL_PE_NO_CYPHERS: - rv = SSL_ERROR_NO_CYPHER_OVERLAP; - break; - case SSL_PE_NO_CERTIFICATE: - rv = SSL_ERROR_NO_CERTIFICATE; - break; - case SSL_PE_BAD_CERTIFICATE: - rv = SSL_ERROR_BAD_CERTIFICATE; - break; - case SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE: - rv = SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE; - break; - default: - goto bad_peer; - } - /* XXX make certificate-request optionally fail... */ - PORT_SetError(rv); - goto loser; - - default: - SSL_DBG(("%d: SSL[%d]: unknown message %d", - SSL_GETPID(), ss->fd, data[0])); - goto loser; - } - - SSL_TRC(3, ("%d: SSL[%d]: handled %d message, required=0x%x got=0x%x", - SSL_GETPID(), ss->fd, data[0], - ss->sec.ci.requiredElements, ss->sec.ci.elements)); - - rv = ssl2_TryToFinish(ss); - if (rv != SECSuccess) - goto loser; - - ss->gs.recordLen = 0; - ssl_ReleaseRecvBufLock(ss); - - if (ss->handshake == 0) { - return SECSuccess; - } - - ss->handshake = ssl_GatherRecord1stHandshake; - ss->nextHandshake = ssl2_HandleMessage; - return ssl2_TriggerNextMessage(ss); - -bad_peer: - PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT : SSL_ERROR_BAD_SERVER); -/* FALL THROUGH */ - -loser: - ssl_ReleaseRecvBufLock(ss); - return SECFailure; -} - -/************************************************************************/ - -/* Called from ssl_Do1stHandshake, after ssl2_HandleServerHelloMessage. -*/ -static SECStatus -ssl2_HandleVerifyMessage(sslSocket *ss) -{ - PRUint8 *data; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - ssl_GetRecvBufLock(ss); - - data = ss->gs.buf.buf + ss->gs.recordOffset; - DUMP_MSG(29, (ss, data, ss->gs.recordLen)); - if ((ss->gs.recordLen != 1 + SSL_CHALLENGE_BYTES) || - (data[0] != SSL_MT_SERVER_VERIFY) || - NSS_SecureMemcmp(data + 1, ss->sec.ci.clientChallenge, - SSL_CHALLENGE_BYTES)) { - /* Bad server */ - PORT_SetError(SSL_ERROR_BAD_SERVER); - goto loser; - } - ss->sec.ci.elements |= CIS_HAVE_VERIFY; - - SSL_TRC(5, ("%d: SSL[%d]: got server-verify, required=0x%d got=0x%x", - SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements, - ss->sec.ci.elements)); - - rv = ssl2_TryToFinish(ss); - if (rv) - goto loser; - - ss->gs.recordLen = 0; - ssl_ReleaseRecvBufLock(ss); - - if (ss->handshake == 0) { - return SECSuccess; - } - ss->handshake = ssl_GatherRecord1stHandshake; - ss->nextHandshake = ssl2_HandleMessage; - return SECSuccess; - -loser: - ssl_ReleaseRecvBufLock(ss); - return SECFailure; -} - -/* Not static because ssl2_GatherData() tests ss->nextHandshake for this value. - * ICK! - * Called from ssl_Do1stHandshake after ssl2_BeginClientHandshake() - */ -SECStatus -ssl2_HandleServerHelloMessage(sslSocket *ss) -{ - sslSessionID *sid; - PRUint8 *cert; - PRUint8 *cs; - PRUint8 *data; - SECStatus rv; - unsigned int needed, sidHit, certLen, csLen, cidLen, certType, err; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - if (!ss->opt.enableSSL2) { - PORT_SetError(SSL_ERROR_SSL2_DISABLED); - return SECFailure; - } - - ssl_GetRecvBufLock(ss); - - PORT_Assert(ss->sec.ci.sid != 0); - sid = ss->sec.ci.sid; - - data = ss->gs.buf.buf + ss->gs.recordOffset; - DUMP_MSG(29, (ss, data, ss->gs.recordLen)); - - /* Make sure first message has some data and is the server hello message */ - if ((ss->gs.recordLen < SSL_HL_SERVER_HELLO_HBYTES) || - (data[0] != SSL_MT_SERVER_HELLO)) { - if ((data[0] == SSL_MT_ERROR) && (ss->gs.recordLen == 3)) { - err = (data[1] << 8) | data[2]; - if (err == SSL_PE_NO_CYPHERS) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - goto loser; - } - } - goto bad_server; - } - - sidHit = data[1]; - certType = data[2]; - ss->version = (data[3] << 8) | data[4]; - certLen = (data[5] << 8) | data[6]; - csLen = (data[7] << 8) | data[8]; - cidLen = (data[9] << 8) | data[10]; - cert = data + SSL_HL_SERVER_HELLO_HBYTES; - cs = cert + certLen; - - SSL_TRC(5, - ("%d: SSL[%d]: server-hello, hit=%d vers=%x certLen=%d csLen=%d cidLen=%d", - SSL_GETPID(), ss->fd, sidHit, ss->version, certLen, - csLen, cidLen)); - if (ss->version != SSL_LIBRARY_VERSION_2) { - if (ss->version < SSL_LIBRARY_VERSION_2) { - SSL_TRC(3, ("%d: SSL[%d]: demoting self (%x) to server version (%x)", - SSL_GETPID(), ss->fd, SSL_LIBRARY_VERSION_2, - ss->version)); - } else { - SSL_TRC(1, ("%d: SSL[%d]: server version is %x (we are %x)", - SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2)); - /* server claims to be newer but does not follow protocol */ - PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); - goto loser; - } - } - - if ((SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen + cidLen > - ss->gs.recordLen) || - (csLen % 3) != 0 - /* || cidLen < SSL_CONNECTIONID_BYTES || cidLen > 32 */ - ) { - goto bad_server; - } - - /* Save connection-id. - ** This code only saves the first 16 byte of the connectionID. - ** If the connectionID is shorter than 16 bytes, it is zero-padded. - */ - if (cidLen < sizeof ss->sec.ci.connectionID) - memset(ss->sec.ci.connectionID, 0, sizeof ss->sec.ci.connectionID); - cidLen = PR_MIN(cidLen, sizeof ss->sec.ci.connectionID); - PORT_Memcpy(ss->sec.ci.connectionID, cs + csLen, cidLen); - - /* See if session-id hit */ - needed = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED | CIS_HAVE_VERIFY; - if (sidHit) { - if (certLen || csLen) { - /* Uh oh - bogus server */ - SSL_DBG(("%d: SSL[%d]: client, huh? hit=%d certLen=%d csLen=%d", - SSL_GETPID(), ss->fd, sidHit, certLen, csLen)); - goto bad_server; - } - - /* Total winner. */ - SSL_TRC(1, ("%d: SSL[%d]: client, using nonce for peer=0x%08x " - "port=0x%04x", - SSL_GETPID(), ss->fd, ss->sec.ci.peer, ss->sec.ci.port)); - ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); - ss->sec.authAlgorithm = sid->authAlgorithm; - ss->sec.authKeyBits = sid->authKeyBits; - ss->sec.keaType = sid->keaType; - ss->sec.keaKeyBits = sid->keaKeyBits; - rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE); - if (rv != SECSuccess) { - goto loser; - } - } else { - if (certType != SSL_CT_X509_CERTIFICATE) { - PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); - goto loser; - } - if (csLen == 0) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - SSL_DBG(("%d: SSL[%d]: no cipher overlap", - SSL_GETPID(), ss->fd)); - goto loser; - } - if (certLen == 0) { - SSL_DBG(("%d: SSL[%d]: client, huh? certLen=%d csLen=%d", - SSL_GETPID(), ss->fd, certLen, csLen)); - goto bad_server; - } - - if (sid->cached != never_cached) { - /* Forget our session-id - server didn't like it */ - SSL_TRC(7, ("%d: SSL[%d]: server forgot me, uncaching session-id", - SSL_GETPID(), ss->fd)); - if (ss->sec.uncache) - (*ss->sec.uncache)(sid); - ssl_FreeSID(sid); - ss->sec.ci.sid = sid = PORT_ZNew(sslSessionID); - if (!sid) { - goto loser; - } - sid->references = 1; - sid->addr = ss->sec.ci.peer; - sid->port = ss->sec.ci.port; - } - - /* decode the server's certificate */ - rv = ssl2_ClientHandleServerCert(ss, cert, certLen); - if (rv != SECSuccess) { - if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) { - (void)ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE); - } - goto loser; - } - - /* Setup new session cipher */ - rv = ssl2_ClientSetupSessionCypher(ss, cs, csLen); - if (rv != SECSuccess) { - if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) { - (void)ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE); - } - goto loser; - } - } - - /* Build up final list of required elements */ - ss->sec.ci.elements = CIS_HAVE_MASTER_KEY; - ss->sec.ci.requiredElements = needed; - - if (!sidHit) { - /* verify the server's certificate. if sidHit, don't check signatures */ - rv = (*ss->authCertificate)(ss->authCertificateArg, ss->fd, - (PRBool)(!sidHit), PR_FALSE); - if (rv) { - if (ss->handleBadCert) { - rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd); - if (rv) { - if (rv == SECWouldBlock) { - SSL_DBG(("%d: SSL[%d]: SSL2 bad cert handler returned " - "SECWouldBlock", - SSL_GETPID(), ss->fd)); - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - rv = SECFailure; - } else { - /* cert is bad */ - SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d", - SSL_GETPID(), ss->fd, PORT_GetError())); - } - goto loser; - } - /* cert is good */ - } else { - SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d", - SSL_GETPID(), ss->fd, PORT_GetError())); - goto loser; - } - } - } - /* - ** At this point we have a completed session key and our session - ** cipher is setup and ready to go. Switch to encrypted write routine - ** as all future message data is to be encrypted. - */ - ssl2_UseEncryptedSendFunc(ss); - - rv = ssl2_TryToFinish(ss); - if (rv != SECSuccess) - goto loser; - - ss->gs.recordLen = 0; - - ssl_ReleaseRecvBufLock(ss); - - if (ss->handshake == 0) { - return SECSuccess; - } - - SSL_TRC(5, ("%d: SSL[%d]: got server-hello, required=0x%d got=0x%x", - SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements, - ss->sec.ci.elements)); - ss->handshake = ssl_GatherRecord1stHandshake; - ss->nextHandshake = ssl2_HandleVerifyMessage; - return SECSuccess; - -bad_server: - PORT_SetError(SSL_ERROR_BAD_SERVER); -/* FALL THROUGH */ - -loser: - ssl_ReleaseRecvBufLock(ss); - return SECFailure; -} - -/* Sends out the initial client Hello message on the connection. - * Acquires and releases the socket's xmitBufLock. - */ -SECStatus -ssl2_BeginClientHandshake(sslSocket *ss) -{ - sslSessionID *sid; - PRUint8 *msg; - PRUint8 *cp; - PRUint8 *localCipherSpecs = NULL; - unsigned int localCipherSize; - unsigned int i; - int sendLen, sidLen = 0; - SECStatus rv; - TLSExtensionData *xtnData; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - ss->sec.isServer = 0; - ss->sec.sendSequence = 0; - ss->sec.rcvSequence = 0; - ssl_ChooseSessionIDProcs(&ss->sec); - - if (!ss->cipherSpecs) { - rv = ssl2_ConstructCipherSpecs(ss); - if (rv != SECSuccess) - goto loser; - } - - /* count the SSL2 and SSL3 enabled ciphers. - * if either is zero, clear the socket's enable for that protocol. - */ - rv = ssl2_CheckConfigSanity(ss); - if (rv != SECSuccess) - goto loser; - - /* Get peer name of server */ - rv = ssl_GetPeerInfo(ss); - if (rv < 0) { -#ifdef HPUX11 - /* - * On some HP-UX B.11.00 systems, getpeername() occasionally - * fails with ENOTCONN after a successful completion of - * non-blocking connect. I found that if we do a write() - * and then retry getpeername(), it will work. - */ - if (PR_GetError() == PR_NOT_CONNECTED_ERROR) { - char dummy; - (void)PR_Write(ss->fd->lower, &dummy, 0); - rv = ssl_GetPeerInfo(ss); - if (rv < 0) { - goto loser; - } - } -#else - goto loser; -#endif - } - - SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd)); - - /* Try to find server in our session-id cache */ - if (ss->opt.noCache) { - sid = NULL; - } else { - sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, - ss->url); - } - while (sid) { /* this isn't really a loop */ - PRBool sidVersionEnabled = - (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) && - sid->version >= ss->vrange.min && - sid->version <= ss->vrange.max) || - (sid->version < SSL_LIBRARY_VERSION_3_0 && ss->opt.enableSSL2); - - /* if we're not doing this SID's protocol any more, drop it. */ - if (!sidVersionEnabled) { - if (ss->sec.uncache) - ss->sec.uncache(sid); - ssl_FreeSID(sid); - sid = NULL; - break; - } - if (sid->version < SSL_LIBRARY_VERSION_3_0) { - /* If the cipher in this sid is not enabled, drop it. */ - for (i = 0; i < ss->sizeCipherSpecs; i += 3) { - if (ss->cipherSpecs[i] == sid->u.ssl2.cipherType) - break; - } - if (i >= ss->sizeCipherSpecs) { - if (ss->sec.uncache) - ss->sec.uncache(sid); - ssl_FreeSID(sid); - sid = NULL; - break; - } - } - sidLen = sizeof(sid->u.ssl2.sessionID); - PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl2.sessionID, - sidLen)); - ss->version = sid->version; - PORT_Assert(!ss->sec.localCert); - if (ss->sec.localCert) { - CERT_DestroyCertificate(ss->sec.localCert); - } - ss->sec.localCert = CERT_DupCertificate(sid->localCert); - break; /* this isn't really a loop */ - } - if (!sid) { - sidLen = 0; - sid = PORT_ZNew(sslSessionID); - if (!sid) { - goto loser; - } - sid->references = 1; - sid->cached = never_cached; - sid->addr = ss->sec.ci.peer; - sid->port = ss->sec.ci.port; - if (ss->peerID != NULL) { - sid->peerID = PORT_Strdup(ss->peerID); - } - if (ss->url != NULL) { - sid->urlSvrName = PORT_Strdup(ss->url); - } - } - ss->sec.ci.sid = sid; - - PORT_Assert(sid != NULL); - - if ((sid->version >= SSL_LIBRARY_VERSION_3_0 || !ss->opt.v2CompatibleHello) && - !SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - ss->gs.state = GS_INIT; - ss->handshake = ssl_GatherRecord1stHandshake; - - /* ssl3_SendClientHello will override this if it succeeds. */ - ss->version = SSL_LIBRARY_VERSION_3_0; - - ssl_GetSSL3HandshakeLock(ss); - ssl_GetXmitBufLock(ss); - rv = ssl3_SendClientHello(ss, PR_FALSE); - ssl_ReleaseXmitBufLock(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - - return rv; - } -#ifndef NSS_DISABLE_ECC - /* ensure we don't neogtiate ECC cipher suites with SSL2 hello */ - ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */ - if (ss->cipherSpecs != NULL) { - PORT_Free(ss->cipherSpecs); - ss->cipherSpecs = NULL; - ss->sizeCipherSpecs = 0; - } -#endif /* NSS_DISABLE_ECC */ - - if (!ss->cipherSpecs) { - rv = ssl2_ConstructCipherSpecs(ss); - if (rv < 0) { - return rv; - } - } - localCipherSpecs = ss->cipherSpecs; - localCipherSize = ss->sizeCipherSpecs; - - /* Add 3 for SCSV */ - sendLen = SSL_HL_CLIENT_HELLO_HBYTES + localCipherSize + 3 + sidLen + - SSL_CHALLENGE_BYTES; - - /* Generate challenge bytes for server */ - PK11_GenerateRandom(ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES); - - ssl_GetXmitBufLock(ss); /***************************************/ - - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv) - goto unlock_loser; - - /* Construct client-hello message */ - cp = msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_CLIENT_HELLO; - ss->clientHelloVersion = SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) ? SSL_LIBRARY_VERSION_2 - : ss->vrange.max; - - msg[1] = MSB(ss->clientHelloVersion); - msg[2] = LSB(ss->clientHelloVersion); - /* Add 3 for SCSV */ - msg[3] = MSB(localCipherSize + 3); - msg[4] = LSB(localCipherSize + 3); - msg[5] = MSB(sidLen); - msg[6] = LSB(sidLen); - msg[7] = MSB(SSL_CHALLENGE_BYTES); - msg[8] = LSB(SSL_CHALLENGE_BYTES); - cp += SSL_HL_CLIENT_HELLO_HBYTES; - PORT_Memcpy(cp, localCipherSpecs, localCipherSize); - cp += localCipherSize; - /* - * Add SCSV. SSL 2.0 cipher suites are listed before SSL 3.0 cipher - * suites in localCipherSpecs for compatibility with SSL 2.0 servers. - * Since SCSV looks like an SSL 3.0 cipher suite, we can't add it at - * the beginning. - */ - cp[0] = 0x00; - cp[1] = 0x00; - cp[2] = 0xff; - cp += 3; - if (sidLen) { - PORT_Memcpy(cp, sid->u.ssl2.sessionID, sidLen); - cp += sidLen; - } - PORT_Memcpy(cp, ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES); - - /* Send it to the server */ - DUMP_MSG(29, (ss, msg, sendLen)); - ss->handshakeBegun = 1; - rv = (*ss->sec.send)(ss, msg, sendLen, 0); - - ssl_ReleaseXmitBufLock(ss); /***************************************/ - - if (rv < 0) { - goto loser; - } - - rv = ssl3_StartHandshakeHash(ss, msg, sendLen); - if (rv < 0) { - goto loser; - } - - /* - * Since we sent the SCSV, pretend we sent empty RI extension. We need - * to record the extension has been advertised after ssl3_InitState has - * been called, which ssl3_StartHandshakeHash took care for us above. - */ - xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = ssl_renegotiation_info_xtn; - - /* Setup to receive servers hello message */ - ssl_GetRecvBufLock(ss); - ss->gs.recordLen = 0; - ssl_ReleaseRecvBufLock(ss); - - ss->handshake = ssl_GatherRecord1stHandshake; - ss->nextHandshake = ssl2_HandleServerHelloMessage; - return SECSuccess; - -unlock_loser: - ssl_ReleaseXmitBufLock(ss); -loser: - return SECFailure; -} - -/************************************************************************/ - -/* Handle the CLIENT-MASTER-KEY message. -** Acquires and releases RecvBufLock. -** Called from ssl2_HandleClientHelloMessage(). -*/ -static SECStatus -ssl2_HandleClientSessionKeyMessage(sslSocket *ss) -{ - PRUint8 *data; - unsigned int caLen; - unsigned int ckLen; - unsigned int ekLen; - unsigned int keyBits; - int cipher; - SECStatus rv; - - ssl_GetRecvBufLock(ss); - - data = ss->gs.buf.buf + ss->gs.recordOffset; - DUMP_MSG(29, (ss, data, ss->gs.recordLen)); - - if ((ss->gs.recordLen < SSL_HL_CLIENT_MASTER_KEY_HBYTES) || - (data[0] != SSL_MT_CLIENT_MASTER_KEY)) { - goto bad_client; - } - cipher = data[1]; - keyBits = (data[2] << 8) | data[3]; - ckLen = (data[4] << 8) | data[5]; - ekLen = (data[6] << 8) | data[7]; - caLen = (data[8] << 8) | data[9]; - - SSL_TRC(5, ("%d: SSL[%d]: session-key, cipher=%d keyBits=%d ckLen=%d ekLen=%d caLen=%d", - SSL_GETPID(), ss->fd, cipher, keyBits, ckLen, ekLen, caLen)); - - if (ss->gs.recordLen < - SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen) { - SSL_DBG(("%d: SSL[%d]: protocol size mismatch dataLen=%d", - SSL_GETPID(), ss->fd, ss->gs.recordLen)); - goto bad_client; - } - - /* Use info from client to setup session key */ - rv = ssl2_ServerSetupSessionCypher(ss, cipher, keyBits, - data + SSL_HL_CLIENT_MASTER_KEY_HBYTES, - ckLen, - data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen, - ekLen, - data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen, - caLen); - ss->gs.recordLen = 0; /* we're done with this record. */ - - ssl_ReleaseRecvBufLock(ss); - - if (rv != SECSuccess) { - goto loser; - } - ss->sec.ci.elements |= CIS_HAVE_MASTER_KEY; - ssl2_UseEncryptedSendFunc(ss); - - /* Send server verify message now that keys are established */ - rv = ssl2_SendServerVerifyMessage(ss); - if (rv != SECSuccess) - goto loser; - - rv = ssl2_TryToFinish(ss); - if (rv != SECSuccess) - goto loser; - if (ss->handshake == 0) { - return SECSuccess; - } - - SSL_TRC(5, ("%d: SSL[%d]: server: waiting for elements=0x%d", - SSL_GETPID(), ss->fd, - ss->sec.ci.requiredElements ^ ss->sec.ci.elements)); - ss->handshake = ssl_GatherRecord1stHandshake; - ss->nextHandshake = ssl2_HandleMessage; - - return ssl2_TriggerNextMessage(ss); - -bad_client: - ssl_ReleaseRecvBufLock(ss); - PORT_SetError(SSL_ERROR_BAD_CLIENT); -/* FALLTHROUGH */ - -loser: - return SECFailure; -} - -/* -** Handle the initial hello message from the client -** -** not static because ssl2_GatherData() tests ss->nextHandshake for this value. -*/ -SECStatus -ssl2_HandleClientHelloMessage(sslSocket *ss) -{ - sslSessionID *sid; - sslServerCerts *sc; - CERTCertificate *serverCert; - PRUint8 *msg; - PRUint8 *data; - PRUint8 *cs; - PRUint8 *sd; - PRUint8 *cert = NULL; - PRUint8 *challenge; - unsigned int challengeLen; - SECStatus rv; - int csLen; - int sendLen; - int sdLen; - int certLen; - int pid; - int sent; - int gotXmitBufLock = 0; -#if defined(SOLARIS) && defined(i386) - volatile PRUint8 hit; -#else - int hit; -#endif - PRUint8 csImpl[sizeof implementedCipherSuites]; - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - sc = ss->serverCerts + kt_rsa; - serverCert = sc->serverCert; - - ssl_GetRecvBufLock(ss); - - data = ss->gs.buf.buf + ss->gs.recordOffset; - DUMP_MSG(29, (ss, data, ss->gs.recordLen)); - - /* Make sure first message has some data and is the client hello message */ - if ((ss->gs.recordLen < SSL_HL_CLIENT_HELLO_HBYTES) || - (data[0] != SSL_MT_CLIENT_HELLO)) { - goto bad_client; - } - - /* Get peer name of client */ - rv = ssl_GetPeerInfo(ss); - if (rv != SECSuccess) { - goto loser; - } - - /* Examine version information */ - /* - * See if this might be a V2 client hello asking to use the V3 protocol - */ - if ((data[0] == SSL_MT_CLIENT_HELLO) && - (data[1] >= MSB(SSL_LIBRARY_VERSION_3_0)) && - !SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) { - rv = ssl3_HandleV2ClientHello(ss, data, ss->gs.recordLen); - if (rv != SECFailure) { /* Success */ - ss->handshake = NULL; - ss->nextHandshake = ssl_GatherRecord1stHandshake; - ss->securityHandshake = NULL; - ss->gs.state = GS_INIT; - - /* ssl3_HandleV3ClientHello has set ss->version, - ** and has gotten us a brand new sid. - */ - ss->sec.ci.sid->version = ss->version; - } - ssl_ReleaseRecvBufLock(ss); - return rv; - } - /* Previously, there was a test here to see if SSL2 was enabled. - ** If not, an error code was set, and SECFailure was returned, - ** without sending any error code to the other end of the connection. - ** That test has been removed. If SSL2 has been disabled, there - ** should be no SSL2 ciphers enabled, and consequently, the code - ** below should send the ssl2 error message SSL_PE_NO_CYPHERS. - ** We now believe this is the correct thing to do, even when SSL2 - ** has been explicitly disabled by the application. - */ - - /* Extract info from message */ - ss->version = (data[1] << 8) | data[2]; - - /* If some client thinks ssl v2 is 2.0 instead of 0.2, we'll allow it. */ - if (ss->version >= SSL_LIBRARY_VERSION_3_0) { - ss->version = SSL_LIBRARY_VERSION_2; - } - - csLen = (data[3] << 8) | data[4]; - sdLen = (data[5] << 8) | data[6]; - challengeLen = (data[7] << 8) | data[8]; - cs = data + SSL_HL_CLIENT_HELLO_HBYTES; - sd = cs + csLen; - challenge = sd + sdLen; - PRINT_BUF(7, (ss, "server, client session-id value:", sd, sdLen)); - - if (!csLen || (csLen % 3) != 0 || - (sdLen != 0 && sdLen != SSL2_SESSIONID_BYTES) || - challengeLen < SSL_MIN_CHALLENGE_BYTES || - challengeLen > SSL_MAX_CHALLENGE_BYTES || - (unsigned)ss->gs.recordLen != - SSL_HL_CLIENT_HELLO_HBYTES + csLen + sdLen + challengeLen) { - SSL_DBG(("%d: SSL[%d]: bad client hello message, len=%d should=%d", - SSL_GETPID(), ss->fd, ss->gs.recordLen, - SSL_HL_CLIENT_HELLO_HBYTES + csLen + sdLen + challengeLen)); - goto bad_client; - } - - SSL_TRC(3, ("%d: SSL[%d]: client version is %x", - SSL_GETPID(), ss->fd, ss->version)); - if (ss->version != SSL_LIBRARY_VERSION_2) { - if (ss->version > SSL_LIBRARY_VERSION_2) { - /* - ** Newer client than us. Things are ok because new clients - ** are required to be backwards compatible with old servers. - ** Change version number to our version number so that client - ** knows whats up. - */ - ss->version = SSL_LIBRARY_VERSION_2; - } else { - SSL_TRC(1, ("%d: SSL[%d]: client version is %x (we are %x)", - SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2)); - PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); - goto loser; - } - } - - /* Qualify cipher specs before returning them to client */ - csLen = ssl2_QualifyCypherSpecs(ss, cs, csLen); - if (csLen == 0) { - /* no overlap, send client our list of supported SSL v2 ciphers. */ - cs = csImpl; - csLen = sizeof implementedCipherSuites; - PORT_Memcpy(cs, implementedCipherSuites, csLen); - csLen = ssl2_QualifyCypherSpecs(ss, cs, csLen); - if (csLen == 0) { - /* We don't support any SSL v2 ciphers! */ - ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS); - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - goto loser; - } - /* Since this handhsake is going to fail, don't cache it. */ - ss->opt.noCache = 1; - } - - /* Squirrel away the challenge for later */ - PORT_Memcpy(ss->sec.ci.clientChallenge, challenge, challengeLen); - - /* Examine message and see if session-id is good */ - ss->sec.ci.elements = 0; - if (sdLen > 0 && !ss->opt.noCache) { - SSL_TRC(7, ("%d: SSL[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x", - SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0], - ss->sec.ci.peer.pr_s6_addr32[1], - ss->sec.ci.peer.pr_s6_addr32[2], - ss->sec.ci.peer.pr_s6_addr32[3])); - sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sd, sdLen, ss->dbHandle); - } else { - sid = NULL; - } - if (sid) { - /* Got a good session-id. Short cut! */ - SSL_TRC(1, ("%d: SSL[%d]: server, using session-id for 0x%08x (age=%d)", - SSL_GETPID(), ss->fd, ss->sec.ci.peer, - ssl_Time() - sid->creationTime)); - PRINT_BUF(1, (ss, "session-id value:", sd, sdLen)); - ss->sec.ci.sid = sid; - ss->sec.ci.elements = CIS_HAVE_MASTER_KEY; - hit = 1; - certLen = 0; - csLen = 0; - - ss->sec.authAlgorithm = sid->authAlgorithm; - ss->sec.authKeyBits = sid->authKeyBits; - ss->sec.keaType = sid->keaType; - ss->sec.keaKeyBits = sid->keaKeyBits; - - rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE); - if (rv != SECSuccess) { - goto loser; - } - } else { - SECItem *derCert = &serverCert->derCert; - - SSL_TRC(7, ("%d: SSL[%d]: server, lookup nonce missed", - SSL_GETPID(), ss->fd)); - if (!serverCert) { - SET_ERROR_CODE - goto loser; - } - hit = 0; - sid = PORT_ZNew(sslSessionID); - if (!sid) { - goto loser; - } - sid->references = 1; - sid->addr = ss->sec.ci.peer; - sid->port = ss->sec.ci.port; - - /* Invent a session-id */ - ss->sec.ci.sid = sid; - PK11_GenerateRandom(sid->u.ssl2.sessionID + 2, SSL2_SESSIONID_BYTES - 2); - - pid = SSL_GETPID(); - sid->u.ssl2.sessionID[0] = MSB(pid); - sid->u.ssl2.sessionID[1] = LSB(pid); - cert = derCert->data; - certLen = derCert->len; - - /* pretend that server sids remember the local cert. */ - PORT_Assert(!sid->localCert); - if (sid->localCert) { - CERT_DestroyCertificate(sid->localCert); - } - sid->localCert = CERT_DupCertificate(serverCert); - - ss->sec.authAlgorithm = ssl_sign_rsa; - ss->sec.keaType = ssl_kea_rsa; - ss->sec.keaKeyBits = - ss->sec.authKeyBits = ss->serverCerts[kt_rsa].serverKeyBits; - } - - /* server sids don't remember the local cert, so whether we found - ** a sid or not, just "remember" we used the rsa server cert. - */ - if (ss->sec.localCert) { - CERT_DestroyCertificate(ss->sec.localCert); - } - ss->sec.localCert = CERT_DupCertificate(serverCert); - - /* Build up final list of required elements */ - ss->sec.ci.requiredElements = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED; - if (ss->opt.requestCertificate) { - ss->sec.ci.requiredElements |= CIS_HAVE_CERTIFICATE; - } - ss->sec.ci.sentElements = 0; - - /* Send hello message back to client */ - sendLen = SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen + - SSL_CONNECTIONID_BYTES; - - ssl_GetXmitBufLock(ss); - gotXmitBufLock = 1; - rv = ssl2_GetSendBuffer(ss, sendLen); - if (rv != SECSuccess) { - goto loser; - } - - SSL_TRC(3, ("%d: SSL[%d]: sending server-hello (%d)", - SSL_GETPID(), ss->fd, sendLen)); - - msg = ss->sec.ci.sendBuf.buf; - msg[0] = SSL_MT_SERVER_HELLO; - msg[1] = hit; - msg[2] = SSL_CT_X509_CERTIFICATE; - msg[3] = MSB(ss->version); - msg[4] = LSB(ss->version); - msg[5] = MSB(certLen); - msg[6] = LSB(certLen); - msg[7] = MSB(csLen); - msg[8] = LSB(csLen); - msg[9] = MSB(SSL_CONNECTIONID_BYTES); - msg[10] = LSB(SSL_CONNECTIONID_BYTES); - if (certLen) { - PORT_Memcpy(msg + SSL_HL_SERVER_HELLO_HBYTES, cert, certLen); - } - if (csLen) { - PORT_Memcpy(msg + SSL_HL_SERVER_HELLO_HBYTES + certLen, cs, csLen); - } - PORT_Memcpy(msg + SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen, - ss->sec.ci.connectionID, SSL_CONNECTIONID_BYTES); - - DUMP_MSG(29, (ss, msg, sendLen)); - - ss->handshakeBegun = 1; - sent = (*ss->sec.send)(ss, msg, sendLen, 0); - if (sent < 0) { - goto loser; - } - ssl_ReleaseXmitBufLock(ss); - gotXmitBufLock = 0; - - ss->gs.recordLen = 0; - ss->handshake = ssl_GatherRecord1stHandshake; - if (hit) { - /* Old SID Session key is good. Go encrypted */ - ssl2_UseEncryptedSendFunc(ss); - - /* Send server verify message now that keys are established */ - rv = ssl2_SendServerVerifyMessage(ss); - if (rv != SECSuccess) - goto loser; - - ss->nextHandshake = ssl2_HandleMessage; - ssl_ReleaseRecvBufLock(ss); - rv = ssl2_TriggerNextMessage(ss); - return rv; - } - ss->nextHandshake = ssl2_HandleClientSessionKeyMessage; - ssl_ReleaseRecvBufLock(ss); - return SECSuccess; - -bad_client: - PORT_SetError(SSL_ERROR_BAD_CLIENT); -/* FALLTHROUGH */ - -loser: - if (gotXmitBufLock) { - ssl_ReleaseXmitBufLock(ss); - gotXmitBufLock = 0; - } - SSL_TRC(10, ("%d: SSL[%d]: server, wait for client-hello lossage", - SSL_GETPID(), ss->fd)); - ssl_ReleaseRecvBufLock(ss); - return SECFailure; -} - -SECStatus -ssl2_BeginServerHandshake(sslSocket *ss) -{ - SECStatus rv; - sslServerCerts *rsaAuth = ss->serverCerts + kt_rsa; - - ss->sec.isServer = 1; - ssl_ChooseSessionIDProcs(&ss->sec); - ss->sec.sendSequence = 0; - ss->sec.rcvSequence = 0; - - /* don't turn on SSL2 if we don't have an RSA key and cert */ - if (!rsaAuth->serverKeyPair || !rsaAuth->SERVERKEY || - !rsaAuth->serverCert) { - ss->opt.enableSSL2 = PR_FALSE; - } - - if (!ss->cipherSpecs) { - rv = ssl2_ConstructCipherSpecs(ss); - if (rv != SECSuccess) - goto loser; - } - - /* count the SSL2 and SSL3 enabled ciphers. - * if either is zero, clear the socket's enable for that protocol. - */ - rv = ssl2_CheckConfigSanity(ss); - if (rv != SECSuccess) - goto loser; - - /* - ** Generate connection-id. Always do this, even if things fail - ** immediately. This way the random number generator is always - ** rolling around, every time we get a connection. - */ - PK11_GenerateRandom(ss->sec.ci.connectionID, - sizeof(ss->sec.ci.connectionID)); - - ss->gs.recordLen = 0; - ss->handshake = ssl_GatherRecord1stHandshake; - ss->nextHandshake = ssl2_HandleClientHelloMessage; - return SECSuccess; - -loser: - return SECFailure; -} - -/* This function doesn't really belong in this file. -** It's here to keep AIX compilers from optimizing it away, -** and not including it in the DSO. -*/ - -#include "nss.h" -extern const char __nss_ssl_version[]; - -PRBool -NSSSSL_VersionCheck(const char *importedVersion) -{ -#define NSS_VERSION_VARIABLE __nss_ssl_version -#include "verref.h" - - /* - * This is the secret handshake algorithm. - * - * This release has a simple version compatibility - * check algorithm. This release is not backward - * compatible with previous major releases. It is - * not compatible with future major, minor, or - * patch releases. - */ - return NSS_VersionCheck(importedVersion); -} - -const char * -NSSSSL_GetVersion(void) -{ - return NSS_VERSION; -}
diff --git a/net/third_party/nss/ssl/ssldef.c b/net/third_party/nss/ssl/ssldef.c deleted file mode 100644 index 77a744cc..0000000 --- a/net/third_party/nss/ssl/ssldef.c +++ /dev/null
@@ -1,224 +0,0 @@ -/* - * "Default" SSLSocket methods, used by sockets that do neither SSL nor socks. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" - -#if defined(WIN32) -#define MAP_ERROR(from, to) \ - if (err == from) { \ - PORT_SetError(to); \ - } -#define DEFINE_ERROR PRErrorCode err = PR_GetError(); -#else -#define MAP_ERROR(from, to) -#define DEFINE_ERROR -#endif - -int -ssl_DefConnect(sslSocket *ss, const PRNetAddr *sa) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->connect(lower, sa, ss->cTimeout); - return rv; -} - -int -ssl_DefBind(sslSocket *ss, const PRNetAddr *addr) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->bind(lower, addr); - return rv; -} - -int -ssl_DefListen(sslSocket *ss, int backlog) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->listen(lower, backlog); - return rv; -} - -int -ssl_DefShutdown(sslSocket *ss, int how) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->shutdown(lower, how); - return rv; -} - -int -ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->recv(lower, (void *)buf, len, flags, ss->rTimeout); - if (rv < 0) { - DEFINE_ERROR - MAP_ERROR(PR_SOCKET_SHUTDOWN_ERROR, PR_CONNECT_RESET_ERROR) - } else if (rv > len) { - PORT_Assert(rv <= len); - PORT_SetError(PR_BUFFER_OVERFLOW_ERROR); - rv = SECFailure; - } - return rv; -} - -/* Default (unencrypted) send. - * For blocking sockets, always returns len or SECFailure, no short writes. - * For non-blocking sockets: - * Returns positive count if any data was written, else returns SECFailure. - * Short writes may occur. Does not return SECWouldBlock. - */ -int -ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags) -{ - PRFileDesc *lower = ss->fd->lower; - int sent = 0; - -#if NSS_DISABLE_NAGLE_DELAYS - /* Although this is overkill, we disable Nagle delays completely for - ** SSL sockets. - */ - if (ss->opt.useSecurity && !ss->delayDisabled) { - ssl_EnableNagleDelay(ss, PR_FALSE); /* ignore error */ - ss->delayDisabled = 1; - } -#endif - do { - int rv = lower->methods->send(lower, (const void *)(buf + sent), - len - sent, flags, ss->wTimeout); - if (rv < 0) { - PRErrorCode err = PR_GetError(); - if (err == PR_WOULD_BLOCK_ERROR) { - ss->lastWriteBlocked = 1; - return sent ? sent : SECFailure; - } - ss->lastWriteBlocked = 0; - MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR) - /* Loser */ - return rv; - } - sent += rv; - - if (IS_DTLS(ss) && (len > sent)) { - /* We got a partial write so just return it */ - return sent; - } - } while (len > sent); - ss->lastWriteBlocked = 0; - return sent; -} - -int -ssl_DefRead(sslSocket *ss, unsigned char *buf, int len) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->read(lower, (void *)buf, len); - if (rv < 0) { - DEFINE_ERROR - MAP_ERROR(PR_SOCKET_SHUTDOWN_ERROR, PR_CONNECT_RESET_ERROR) - } - return rv; -} - -int -ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len) -{ - PRFileDesc *lower = ss->fd->lower; - int sent = 0; - - do { - int rv = lower->methods->write(lower, (const void *)(buf + sent), - len - sent); - if (rv < 0) { - PRErrorCode err = PR_GetError(); - if (err == PR_WOULD_BLOCK_ERROR) { - ss->lastWriteBlocked = 1; - return sent ? sent : SECFailure; - } - ss->lastWriteBlocked = 0; - MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR) - /* Loser */ - return rv; - } - sent += rv; - } while (len > sent); - ss->lastWriteBlocked = 0; - return sent; -} - -int -ssl_DefGetpeername(sslSocket *ss, PRNetAddr *name) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->getpeername(lower, name); - return rv; -} - -int -ssl_DefGetsockname(sslSocket *ss, PRNetAddr *name) -{ - PRFileDesc *lower = ss->fd->lower; - int rv; - - rv = lower->methods->getsockname(lower, name); - return rv; -} - -int -ssl_DefClose(sslSocket *ss) -{ - PRFileDesc *fd; - PRFileDesc *popped; - int rv; - - fd = ss->fd; - - /* First, remove the SSL layer PRFileDesc from the socket's stack, - ** then invoke the SSL layer's PRFileDesc destructor. - ** This must happen before the next layer down is closed. - */ - PORT_Assert(fd->higher == NULL); - if (fd->higher) { - PORT_SetError(PR_BAD_DESCRIPTOR_ERROR); - return SECFailure; - } - ss->fd = NULL; - - /* PR_PopIOLayer will swap the contents of the top two PRFileDescs on - ** the stack, and then remove the second one. This way, the address - ** of the PRFileDesc on the top of the stack doesn't change. - */ - popped = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); - popped->dtor(popped); - - /* fd is now the PRFileDesc for the next layer down. - ** Now close the underlying socket. - */ - rv = fd->methods->close(fd); - - ssl_FreeSocket(ss); - - SSL_TRC(5, ("%d: SSL[%d]: closing, rv=%d errno=%d", - SSL_GETPID(), fd, rv, PORT_GetError())); - return rv; -}
diff --git a/net/third_party/nss/ssl/sslenum.c b/net/third_party/nss/ssl/sslenum.c deleted file mode 100644 index d362b74..0000000 --- a/net/third_party/nss/ssl/sslenum.c +++ /dev/null
@@ -1,163 +0,0 @@ -/* - * Table enumerating all implemented cipher suites - * Part of public API. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ssl.h" -#include "sslproto.h" - -/* - * The ordering of cipher suites in this table must match the ordering in - * the cipherSuites table in ssl3con.c. - * - * If new ECC cipher suites are added, also update the ssl3CipherSuite arrays - * in ssl3ecc.c. - * - * Finally, update the ssl_V3_SUITES_IMPLEMENTED macro in sslimpl.h. - * - * The ordering is as follows: - * * No-encryption cipher suites last - * * Export/weak/obsolete cipher suites before no-encryption cipher suites - * * Order by key exchange algorithm: ECDHE, then DHE, then ECDH, RSA. - * * Within key agreement sections, order by symmetric encryption algorithm: - * AES-128, then Camellia-128, then AES-256, then Camellia-256, then SEED, - * then FIPS-3DES, then 3DES, then RC4. AES is commonly accepted as a - * strong cipher internationally, and is often hardware-accelerated. - * Camellia also has wide international support across standards - * organizations. SEED is only recommended by the Korean government. 3DES - * only provides 112 bits of security. RC4 is now deprecated or forbidden - * by many standards organizations. - * * Within symmetric algorithm sections, order by message authentication - * algorithm: GCM, then HMAC-SHA1, then HMAC-SHA256, then HMAC-MD5. - * * Within message authentication algorithm sections, order by asymmetric - * signature algorithm: ECDSA, then RSA, then DSS. - * - * Exception: Because some servers ignore the high-order byte of the cipher - * suite ID, we must be careful about adding cipher suites with IDs larger - * than 0x00ff; see bug 946147. For these broken servers, the first four cipher - * suites, with the MSB zeroed, look like: - * TLS_KRB5_EXPORT_WITH_RC4_40_MD5 { 0x00,0x2B } - * TLS_RSA_WITH_AES_128_CBC_SHA { 0x00,0x2F } - * TLS_RSA_WITH_3DES_EDE_CBC_SHA { 0x00,0x0A } - * TLS_RSA_WITH_DES_CBC_SHA { 0x00,0x09 } - * The broken server only supports the third and fourth ones and will select - * the third one. - */ -const PRUint16 SSL_ImplementedCiphers[] = { -#ifndef NSS_DISABLE_ECC - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA must appear before - * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA to work around bug 946147. - */ - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS_ECDHE_RSA_WITH_RC4_128_SHA, -#endif /* NSS_DISABLE_ECC */ - - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - TLS_DHE_DSS_WITH_RC4_128_SHA, - -#ifndef NSS_DISABLE_ECC - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - TLS_ECDH_RSA_WITH_RC4_128_SHA, -#endif /* NSS_DISABLE_ECC */ - - TLS_RSA_WITH_AES_128_GCM_SHA256, - TLS_RSA_WITH_AES_128_CBC_SHA, - TLS_RSA_WITH_AES_128_CBC_SHA256, - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, - TLS_RSA_WITH_AES_256_CBC_SHA, - TLS_RSA_WITH_AES_256_CBC_SHA256, - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, - TLS_RSA_WITH_SEED_CBC_SHA, - SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, - TLS_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_RSA_WITH_RC4_128_SHA, - TLS_RSA_WITH_RC4_128_MD5, - - /* 56-bit DES "domestic" cipher suites */ - TLS_DHE_RSA_WITH_DES_CBC_SHA, - TLS_DHE_DSS_WITH_DES_CBC_SHA, - SSL_RSA_FIPS_WITH_DES_CBC_SHA, - TLS_RSA_WITH_DES_CBC_SHA, - - /* export ciphersuites with 1024-bit public key exchange keys */ - TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, - - /* export ciphersuites with 512-bit public key exchange keys */ - TLS_RSA_EXPORT_WITH_RC4_40_MD5, - TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, - -/* ciphersuites with no encryption */ -#ifndef NSS_DISABLE_ECC - TLS_ECDHE_ECDSA_WITH_NULL_SHA, - TLS_ECDHE_RSA_WITH_NULL_SHA, - TLS_ECDH_RSA_WITH_NULL_SHA, - TLS_ECDH_ECDSA_WITH_NULL_SHA, -#endif /* NSS_DISABLE_ECC */ - TLS_RSA_WITH_NULL_SHA, - TLS_RSA_WITH_NULL_SHA256, - TLS_RSA_WITH_NULL_MD5, - - /* SSL2 cipher suites. */ - SSL_EN_RC4_128_WITH_MD5, - SSL_EN_RC2_128_CBC_WITH_MD5, - SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* actually 112, not 192 */ - SSL_EN_DES_64_CBC_WITH_MD5, - SSL_EN_RC4_128_EXPORT40_WITH_MD5, - SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, - - 0 - -}; - -const PRUint16 SSL_NumImplementedCiphers = - (sizeof SSL_ImplementedCiphers) / (sizeof SSL_ImplementedCiphers[0]) - 1; - -const PRUint16* -SSL_GetImplementedCiphers(void) -{ - return SSL_ImplementedCiphers; -} - -PRUint16 -SSL_GetNumImplementedCiphers(void) -{ - return SSL_NumImplementedCiphers; -}
diff --git a/net/third_party/nss/ssl/sslerr.c b/net/third_party/nss/ssl/sslerr.c deleted file mode 100644 index edb9412..0000000 --- a/net/third_party/nss/ssl/sslerr.c +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * Function to set error code only when meaningful error has not already - * been set. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prerror.h" -#include "secerr.h" -#include "sslerr.h" -#include "seccomon.h" - -/* look at the current value of PR_GetError, and evaluate it to see - * if it is meaningful or meaningless (out of context). - * If it is meaningless, replace it with the hiLevelError. - * Returns the chosen error value. - */ -int -ssl_MapLowLevelError(int hiLevelError) -{ - int oldErr = PORT_GetError(); - - switch (oldErr) { - - case 0: - case PR_IO_ERROR: - case SEC_ERROR_IO: - case SEC_ERROR_BAD_DATA: - case SEC_ERROR_LIBRARY_FAILURE: - case SEC_ERROR_EXTENSION_NOT_FOUND: - case SSL_ERROR_BAD_CLIENT: - case SSL_ERROR_BAD_SERVER: - case SSL_ERROR_SESSION_NOT_FOUND: - PORT_SetError(hiLevelError); - return hiLevelError; - - default: /* leave the majority of error codes alone. */ - return oldErr; - } -}
diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h deleted file mode 100644 index 299951c..0000000 --- a/net/third_party/nss/ssl/sslerr.h +++ /dev/null
@@ -1,234 +0,0 @@ -/* - * Enumeration of all SSL-specific error codes. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef __SSL_ERR_H_ -#define __SSL_ERR_H_ - -/* clang-format off */ - -#define SSL_ERROR_BASE (-0x3000) -#define SSL_ERROR_LIMIT (SSL_ERROR_BASE + 1000) - -#define IS_SSL_ERROR(code) \ - (((code) >= SSL_ERROR_BASE) && ((code) < SSL_ERROR_LIMIT)) - -#ifndef NO_SECURITY_ERROR_ENUM -typedef enum { - SSL_ERROR_EXPORT_ONLY_SERVER = (SSL_ERROR_BASE + 0), - SSL_ERROR_US_ONLY_SERVER = (SSL_ERROR_BASE + 1), - SSL_ERROR_NO_CYPHER_OVERLAP = (SSL_ERROR_BASE + 2), - /* - * Received an alert reporting what we did wrong. (more alerts below) - */ - SSL_ERROR_NO_CERTIFICATE /*_ALERT */ = (SSL_ERROR_BASE + 3), - SSL_ERROR_BAD_CERTIFICATE = (SSL_ERROR_BASE + 4), - SSL_ERROR_UNUSED_5 = (SSL_ERROR_BASE + 5), - /* error 5 is obsolete */ - SSL_ERROR_BAD_CLIENT = (SSL_ERROR_BASE + 6), - SSL_ERROR_BAD_SERVER = (SSL_ERROR_BASE + 7), - SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE = (SSL_ERROR_BASE + 8), - SSL_ERROR_UNSUPPORTED_VERSION = (SSL_ERROR_BASE + 9), - SSL_ERROR_UNUSED_10 = (SSL_ERROR_BASE + 10), - /* error 10 is obsolete */ - SSL_ERROR_WRONG_CERTIFICATE = (SSL_ERROR_BASE + 11), - SSL_ERROR_BAD_CERT_DOMAIN = (SSL_ERROR_BASE + 12), - SSL_ERROR_POST_WARNING = (SSL_ERROR_BASE + 13), - SSL_ERROR_SSL2_DISABLED = (SSL_ERROR_BASE + 14), - SSL_ERROR_BAD_MAC_READ = (SSL_ERROR_BASE + 15), - /* - * Received an alert reporting what we did wrong. - * (two more alerts above, and many more below) - */ - SSL_ERROR_BAD_MAC_ALERT = (SSL_ERROR_BASE + 16), - SSL_ERROR_BAD_CERT_ALERT = (SSL_ERROR_BASE + 17), - SSL_ERROR_REVOKED_CERT_ALERT = (SSL_ERROR_BASE + 18), - SSL_ERROR_EXPIRED_CERT_ALERT = (SSL_ERROR_BASE + 19), - - SSL_ERROR_SSL_DISABLED = (SSL_ERROR_BASE + 20), - SSL_ERROR_FORTEZZA_PQG = (SSL_ERROR_BASE + 21), - SSL_ERROR_UNKNOWN_CIPHER_SUITE = (SSL_ERROR_BASE + 22), - SSL_ERROR_NO_CIPHERS_SUPPORTED = (SSL_ERROR_BASE + 23), - SSL_ERROR_BAD_BLOCK_PADDING = (SSL_ERROR_BASE + 24), - SSL_ERROR_RX_RECORD_TOO_LONG = (SSL_ERROR_BASE + 25), - SSL_ERROR_TX_RECORD_TOO_LONG = (SSL_ERROR_BASE + 26), - /* - * Received a malformed (too long or short) SSL handshake. - */ - SSL_ERROR_RX_MALFORMED_HELLO_REQUEST = (SSL_ERROR_BASE + 27), - SSL_ERROR_RX_MALFORMED_CLIENT_HELLO = (SSL_ERROR_BASE + 28), - SSL_ERROR_RX_MALFORMED_SERVER_HELLO = (SSL_ERROR_BASE + 29), - SSL_ERROR_RX_MALFORMED_CERTIFICATE = (SSL_ERROR_BASE + 30), - SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH = (SSL_ERROR_BASE + 31), - SSL_ERROR_RX_MALFORMED_CERT_REQUEST = (SSL_ERROR_BASE + 32), - SSL_ERROR_RX_MALFORMED_HELLO_DONE = (SSL_ERROR_BASE + 33), - SSL_ERROR_RX_MALFORMED_CERT_VERIFY = (SSL_ERROR_BASE + 34), - SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH = (SSL_ERROR_BASE + 35), - SSL_ERROR_RX_MALFORMED_FINISHED = (SSL_ERROR_BASE + 36), - /* - * Received a malformed (too long or short) SSL record. - */ - SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER = (SSL_ERROR_BASE + 37), - SSL_ERROR_RX_MALFORMED_ALERT = (SSL_ERROR_BASE + 38), - SSL_ERROR_RX_MALFORMED_HANDSHAKE = (SSL_ERROR_BASE + 39), - SSL_ERROR_RX_MALFORMED_APPLICATION_DATA = (SSL_ERROR_BASE + 40), - /* - * Received an SSL handshake that was inappropriate for the state we're in. - * E.g. Server received message from server, or wrong state in state machine. - */ - SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST = (SSL_ERROR_BASE + 41), - SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO = (SSL_ERROR_BASE + 42), - SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO = (SSL_ERROR_BASE + 43), - SSL_ERROR_RX_UNEXPECTED_CERTIFICATE = (SSL_ERROR_BASE + 44), - SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH = (SSL_ERROR_BASE + 45), - SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST = (SSL_ERROR_BASE + 46), - SSL_ERROR_RX_UNEXPECTED_HELLO_DONE = (SSL_ERROR_BASE + 47), - SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY = (SSL_ERROR_BASE + 48), - SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH = (SSL_ERROR_BASE + 49), - SSL_ERROR_RX_UNEXPECTED_FINISHED = (SSL_ERROR_BASE + 50), - /* - * Received an SSL record that was inappropriate for the state we're in. - */ - SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER = (SSL_ERROR_BASE + 51), - SSL_ERROR_RX_UNEXPECTED_ALERT = (SSL_ERROR_BASE + 52), - SSL_ERROR_RX_UNEXPECTED_HANDSHAKE = (SSL_ERROR_BASE + 53), - SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA = (SSL_ERROR_BASE + 54), - /* - * Received record/message with unknown discriminant. - */ - SSL_ERROR_RX_UNKNOWN_RECORD_TYPE = (SSL_ERROR_BASE + 55), - SSL_ERROR_RX_UNKNOWN_HANDSHAKE = (SSL_ERROR_BASE + 56), - SSL_ERROR_RX_UNKNOWN_ALERT = (SSL_ERROR_BASE + 57), - /* - * Received an alert reporting what we did wrong. (more alerts above) - */ - SSL_ERROR_CLOSE_NOTIFY_ALERT = (SSL_ERROR_BASE + 58), - SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT = (SSL_ERROR_BASE + 59), - SSL_ERROR_DECOMPRESSION_FAILURE_ALERT = (SSL_ERROR_BASE + 60), - SSL_ERROR_HANDSHAKE_FAILURE_ALERT = (SSL_ERROR_BASE + 61), - SSL_ERROR_ILLEGAL_PARAMETER_ALERT = (SSL_ERROR_BASE + 62), - SSL_ERROR_UNSUPPORTED_CERT_ALERT = (SSL_ERROR_BASE + 63), - SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT = (SSL_ERROR_BASE + 64), - - SSL_ERROR_GENERATE_RANDOM_FAILURE = (SSL_ERROR_BASE + 65), - SSL_ERROR_SIGN_HASHES_FAILURE = (SSL_ERROR_BASE + 66), - SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE = (SSL_ERROR_BASE + 67), - SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 68), - SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 69), - - SSL_ERROR_ENCRYPTION_FAILURE = (SSL_ERROR_BASE + 70), - SSL_ERROR_DECRYPTION_FAILURE = (SSL_ERROR_BASE + 71), /* don't use */ - SSL_ERROR_SOCKET_WRITE_FAILURE = (SSL_ERROR_BASE + 72), - - SSL_ERROR_MD5_DIGEST_FAILURE = (SSL_ERROR_BASE + 73), - SSL_ERROR_SHA_DIGEST_FAILURE = (SSL_ERROR_BASE + 74), - SSL_ERROR_MAC_COMPUTATION_FAILURE = (SSL_ERROR_BASE + 75), - SSL_ERROR_SYM_KEY_CONTEXT_FAILURE = (SSL_ERROR_BASE + 76), - SSL_ERROR_SYM_KEY_UNWRAP_FAILURE = (SSL_ERROR_BASE + 77), - SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED = (SSL_ERROR_BASE + 78), - SSL_ERROR_IV_PARAM_FAILURE = (SSL_ERROR_BASE + 79), - SSL_ERROR_INIT_CIPHER_SUITE_FAILURE = (SSL_ERROR_BASE + 80), - SSL_ERROR_SESSION_KEY_GEN_FAILURE = (SSL_ERROR_BASE + 81), - SSL_ERROR_NO_SERVER_KEY_FOR_ALG = (SSL_ERROR_BASE + 82), - SSL_ERROR_TOKEN_INSERTION_REMOVAL = (SSL_ERROR_BASE + 83), - SSL_ERROR_TOKEN_SLOT_NOT_FOUND = (SSL_ERROR_BASE + 84), - SSL_ERROR_NO_COMPRESSION_OVERLAP = (SSL_ERROR_BASE + 85), - SSL_ERROR_HANDSHAKE_NOT_COMPLETED = (SSL_ERROR_BASE + 86), - SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE = (SSL_ERROR_BASE + 87), - SSL_ERROR_CERT_KEA_MISMATCH = (SSL_ERROR_BASE + 88), - /* SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA became obsolete in NSS 3.14. */ - SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA = (SSL_ERROR_BASE + 89), - SSL_ERROR_SESSION_NOT_FOUND = (SSL_ERROR_BASE + 90), - - SSL_ERROR_DECRYPTION_FAILED_ALERT = (SSL_ERROR_BASE + 91), - SSL_ERROR_RECORD_OVERFLOW_ALERT = (SSL_ERROR_BASE + 92), - SSL_ERROR_UNKNOWN_CA_ALERT = (SSL_ERROR_BASE + 93), - SSL_ERROR_ACCESS_DENIED_ALERT = (SSL_ERROR_BASE + 94), - SSL_ERROR_DECODE_ERROR_ALERT = (SSL_ERROR_BASE + 95), - SSL_ERROR_DECRYPT_ERROR_ALERT = (SSL_ERROR_BASE + 96), - SSL_ERROR_EXPORT_RESTRICTION_ALERT = (SSL_ERROR_BASE + 97), - SSL_ERROR_PROTOCOL_VERSION_ALERT = (SSL_ERROR_BASE + 98), - SSL_ERROR_INSUFFICIENT_SECURITY_ALERT = (SSL_ERROR_BASE + 99), - SSL_ERROR_INTERNAL_ERROR_ALERT = (SSL_ERROR_BASE + 100), - SSL_ERROR_USER_CANCELED_ALERT = (SSL_ERROR_BASE + 101), - SSL_ERROR_NO_RENEGOTIATION_ALERT = (SSL_ERROR_BASE + 102), - - SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED = (SSL_ERROR_BASE + 103), - - SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT = (SSL_ERROR_BASE + 104), - SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT = (SSL_ERROR_BASE + 105), - SSL_ERROR_UNRECOGNIZED_NAME_ALERT = (SSL_ERROR_BASE + 106), - SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT = (SSL_ERROR_BASE + 107), - SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT = (SSL_ERROR_BASE + 108), - - SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 109), - SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 110), - - SSL_ERROR_DECOMPRESSION_FAILURE = (SSL_ERROR_BASE + 111), - SSL_ERROR_RENEGOTIATION_NOT_ALLOWED = (SSL_ERROR_BASE + 112), - SSL_ERROR_UNSAFE_NEGOTIATION = (SSL_ERROR_BASE + 113), - - SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114), - - SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY = (SSL_ERROR_BASE + 115), - - SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID = (SSL_ERROR_BASE + 116), - - SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2 = (SSL_ERROR_BASE + 117), - SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS = (SSL_ERROR_BASE + 118), - SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS = (SSL_ERROR_BASE + 119), - - SSL_ERROR_INVALID_VERSION_RANGE = (SSL_ERROR_BASE + 120), - SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 121), - - SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 122), - SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 123), - - SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION = (SSL_ERROR_BASE + 124), - - SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 125), - - SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM = (SSL_ERROR_BASE + 126), - SSL_ERROR_DIGEST_FAILURE = (SSL_ERROR_BASE + 127), - SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128), - - SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK = (SSL_ERROR_BASE + 129), - SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL = (SSL_ERROR_BASE + 130), - - SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT = (SSL_ERROR_BASE + 131), - - SSL_ERROR_WEAK_SERVER_CERT_KEY = (SSL_ERROR_BASE + 132), - - SSL_ERROR_RX_SHORT_DTLS_READ = (SSL_ERROR_BASE + 133), - - SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 134), - SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 135), - - SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET = (SSL_ERROR_BASE + 136), - SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET = (SSL_ERROR_BASE + 137), - - SSL_ERROR_RX_MALFORMED_KEY_SHARE = (SSL_ERROR_BASE + 138), - SSL_ERROR_MISSING_KEY_SHARE = (SSL_ERROR_BASE + 139), - SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE = (SSL_ERROR_BASE + 140), - SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE = (SSL_ERROR_BASE + 141), - - SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 142), - SSL_ERROR_MISSING_EXTENSION_ALERT = (SSL_ERROR_BASE + 143), - - SSL_ERROR_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 144), - SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 145), - SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 146), - - SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 147), - SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 148), - SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 149), - - SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ -} SSLErrorCodes; -#endif /* NO_SECURITY_ERROR_ENUM */ - -/* clang-format on */ - -#endif /* __SSL_ERR_H_ */
diff --git a/net/third_party/nss/ssl/sslerrstrs.c b/net/third_party/nss/ssl/sslerrstrs.c deleted file mode 100644 index 4e3db6d..0000000 --- a/net/third_party/nss/ssl/sslerrstrs.c +++ /dev/null
@@ -1,36 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "prerror.h" -#include "sslerr.h" -#include "prinit.h" -#include "nssutil.h" -#include "ssl.h" - -#define ER3(name, value, str) { #name, str }, - -static const struct PRErrorMessage ssltext[] = { -#include "SSLerrs.h" - { 0, 0 } -}; - -static const struct PRErrorTable ssl_et = { - ssltext, "sslerr", SSL_ERROR_BASE, - (sizeof ssltext) / (sizeof ssltext[0]) -}; - -static PRStatus -ssl_InitializePRErrorTableOnce(void) -{ - return PR_ErrorInstallTable(&ssl_et); -} - -static PRCallOnceType once; - -SECStatus -ssl_InitializePRErrorTable(void) -{ - return (PR_SUCCESS == PR_CallOnce(&once, ssl_InitializePRErrorTableOnce)) - ? SECSuccess - : SECFailure; -}
diff --git a/net/third_party/nss/ssl/sslgathr.c b/net/third_party/nss/ssl/sslgathr.c deleted file mode 100644 index 48d615e..0000000 --- a/net/third_party/nss/ssl/sslgathr.c +++ /dev/null
@@ -1,421 +0,0 @@ -/* - * Gather (Read) entire SSL2 records from socket into buffer. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" - -/* Forward static declarations */ -static SECStatus ssl2_HandleV3HandshakeRecord(sslSocket *ss); - -/* -** Gather a single record of data from the receiving stream. This code -** first gathers the header (2 or 3 bytes long depending on the value of -** the most significant bit in the first byte) then gathers up the data -** for the record into gs->buf. This code handles non-blocking I/O -** and is to be called multiple times until ss->sec.recordLen != 0. -** This function decrypts the gathered record in place, in gs_buf. - * - * Caller must hold RecvBufLock. - * - * Returns +1 when it has gathered a complete SSLV2 record. - * Returns 0 if it hits EOF. - * Returns -1 (SECFailure) on any error - * Returns -2 (SECWouldBlock) when it gathers an SSL v3 client hello header. -** -** The SSL2 Gather State machine has 4 states: -** GS_INIT - Done reading in previous record. Haven't begun to read in -** next record. When ssl2_GatherData is called with the machine -** in this state, the machine will attempt to read the first 3 -** bytes of the SSL2 record header, and will advance the state -** to GS_HEADER. -** -** GS_HEADER - The machine is in this state while waiting for the completion -** of the first 3 bytes of the SSL2 record. When complete, the -** machine will compute the remaining unread length of this record -** and will initiate a read of that many bytes. The machine will -** advance to one of two states, depending on whether the record -** is encrypted (GS_MAC), or unencrypted (GS_DATA). -** -** GS_MAC - The machine is in this state while waiting for the remainder -** of the SSL2 record to be read in. When the read is completed, -** the machine checks the record for valid length, decrypts it, -** and checks and discards the MAC, then advances to GS_INIT. -** -** GS_DATA - The machine is in this state while waiting for the remainder -** of the unencrypted SSL2 record to be read in. Upon completion, -** the machine advances to the GS_INIT state and returns the data. -*/ -int -ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags) -{ - unsigned char *bp; - unsigned char *pBuf; - int nb, err, rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - if (gs->state == GS_INIT) { - /* Initialize gathering engine */ - gs->state = GS_HEADER; - gs->remainder = 3; - gs->count = 3; - gs->offset = 0; - gs->recordLen = 0; - gs->recordPadding = 0; - gs->hdr[2] = 0; - - gs->writeOffset = 0; - gs->readOffset = 0; - } - if (gs->encrypted) { - PORT_Assert(ss->sec.hash != 0); - } - - pBuf = gs->buf.buf; - for (;;) { - SSL_TRC(30, ("%d: SSL[%d]: gather state %d (need %d more)", - SSL_GETPID(), ss->fd, gs->state, gs->remainder)); - bp = ((gs->state != GS_HEADER) ? pBuf : gs->hdr) + gs->offset; - nb = ssl_DefRecv(ss, bp, gs->remainder, flags); - if (nb > 0) { - PRINT_BUF(60, (ss, "raw gather data:", bp, nb)); - } - if (nb == 0) { - /* EOF */ - SSL_TRC(30, ("%d: SSL[%d]: EOF", SSL_GETPID(), ss->fd)); - rv = 0; - break; - } - if (nb < 0) { - SSL_DBG(("%d: SSL[%d]: recv error %d", SSL_GETPID(), ss->fd, - PR_GetError())); - rv = SECFailure; - break; - } - - gs->offset += nb; - gs->remainder -= nb; - - if (gs->remainder > 0) { - continue; - } - - /* Probably finished this piece */ - switch (gs->state) { - case GS_HEADER: - if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) && !ss->firstHsDone) { - - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - /* If this looks like an SSL3 handshake record, - ** and we're expecting an SSL2 Hello message from our peer, - ** handle it here. - */ - if (gs->hdr[0] == content_handshake) { - if ((ss->nextHandshake == ssl2_HandleClientHelloMessage) || - (ss->nextHandshake == ssl2_HandleServerHelloMessage)) { - rv = ssl2_HandleV3HandshakeRecord(ss); - if (rv == SECFailure) { - return SECFailure; - } - } - /* XXX_1 The call stack to here is: - * ssl_Do1stHandshake -> ssl_GatherRecord1stHandshake -> - * ssl2_GatherRecord -> here. - * We want to return all the way out to ssl_Do1stHandshake, - * and have it call ssl_GatherRecord1stHandshake again. - * ssl_GatherRecord1stHandshake will call - * ssl3_GatherCompleteHandshake when it is called again. - * - * Returning SECWouldBlock here causes - * ssl_GatherRecord1stHandshake to return without clearing - * ss->handshake, ensuring that ssl_Do1stHandshake will - * call it again immediately. - * - * If we return 1 here, ssl_GatherRecord1stHandshake will - * clear ss->handshake before returning, and thus will not - * be called again by ssl_Do1stHandshake. - */ - return SECWouldBlock; - } else if (gs->hdr[0] == content_alert) { - if (ss->nextHandshake == ssl2_HandleServerHelloMessage) { - /* XXX This is a hack. We're assuming that any failure - * XXX on the client hello is a failure to match - * XXX ciphers. - */ - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return SECFailure; - } - } - } - - /* we've got the first 3 bytes. The header may be two or three. */ - if (gs->hdr[0] & 0x80) { - /* This record has a 2-byte header, and no padding */ - gs->count = ((gs->hdr[0] & 0x7f) << 8) | gs->hdr[1]; - gs->recordPadding = 0; - } else { - /* This record has a 3-byte header that is all read in now. */ - gs->count = ((gs->hdr[0] & 0x3f) << 8) | gs->hdr[1]; - /* is_escape = (gs->hdr[0] & 0x40) != 0; */ - gs->recordPadding = gs->hdr[2]; - } - if (!gs->count) { - PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); - goto cleanup; - } - - if (gs->count > gs->buf.space) { - err = sslBuffer_Grow(&gs->buf, gs->count); - if (err) { - return err; - } - pBuf = gs->buf.buf; - } - - if (gs->hdr[0] & 0x80) { - /* we've already read in the first byte of the body. - ** Put it into the buffer. - */ - pBuf[0] = gs->hdr[2]; - gs->offset = 1; - gs->remainder = gs->count - 1; - } else { - gs->offset = 0; - gs->remainder = gs->count; - } - - if (gs->encrypted) { - gs->state = GS_MAC; - gs->recordLen = gs->count - gs->recordPadding - - ss->sec.hash->length; - } else { - gs->state = GS_DATA; - gs->recordLen = gs->count; - } - - break; - - case GS_MAC: - /* Have read in entire rest of the ciphertext. - ** Check for valid length. - ** Decrypt it. - ** Check the MAC. - */ - PORT_Assert(gs->encrypted); - - { - unsigned int macLen; - int nout; - unsigned char mac[SSL_MAX_MAC_BYTES]; - - ssl_GetSpecReadLock(ss); /**********************************/ - - /* If this is a stream cipher, blockSize will be 1, - * and this test will always be false. - * If this is a block cipher, this will detect records - * that are not a multiple of the blocksize in length. - */ - if (gs->count & (ss->sec.blockSize - 1)) { - /* This is an error. Sender is misbehaving */ - SSL_DBG(("%d: SSL[%d]: sender, count=%d blockSize=%d", - SSL_GETPID(), ss->fd, gs->count, - ss->sec.blockSize)); - PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING); - rv = SECFailure; - goto spec_locked_done; - } - PORT_Assert(gs->count == gs->offset); - - if (gs->offset == 0) { - rv = 0; /* means EOF. */ - goto spec_locked_done; - } - - /* Decrypt the portion of data that we just received. - ** Decrypt it in place. - */ - rv = (*ss->sec.dec)(ss->sec.readcx, pBuf, &nout, gs->offset, - pBuf, gs->offset); - if (rv != SECSuccess) { - goto spec_locked_done; - } - - /* Have read in all the MAC portion of record - ** - ** Prepare MAC by resetting it and feeding it the shared secret - */ - macLen = ss->sec.hash->length; - if (gs->offset >= macLen) { - PRUint32 sequenceNumber = ss->sec.rcvSequence++; - unsigned char seq[4]; - - seq[0] = (unsigned char)(sequenceNumber >> 24); - seq[1] = (unsigned char)(sequenceNumber >> 16); - seq[2] = (unsigned char)(sequenceNumber >> 8); - seq[3] = (unsigned char)(sequenceNumber); - - (*ss->sec.hash->begin)(ss->sec.hashcx); - (*ss->sec.hash->update)(ss->sec.hashcx, ss->sec.rcvSecret.data, - ss->sec.rcvSecret.len); - (*ss->sec.hash->update)(ss->sec.hashcx, pBuf + macLen, - gs->offset - macLen); - (*ss->sec.hash->update)(ss->sec.hashcx, seq, 4); - (*ss->sec.hash->end)(ss->sec.hashcx, mac, &macLen, macLen); - - PORT_Assert(macLen == ss->sec.hash->length); - - ssl_ReleaseSpecReadLock(ss); /******************************/ - - if (NSS_SecureMemcmp(mac, pBuf, macLen) != 0) { - /* MAC's didn't match... */ - SSL_DBG(("%d: SSL[%d]: mac check failed, seq=%d", - SSL_GETPID(), ss->fd, ss->sec.rcvSequence)); - PRINT_BUF(1, (ss, "computed mac:", mac, macLen)); - PRINT_BUF(1, (ss, "received mac:", pBuf, macLen)); - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - rv = SECFailure; - goto cleanup; - } - } else { - ssl_ReleaseSpecReadLock(ss); /******************************/ - } - - if (gs->recordPadding + macLen <= gs->offset) { - gs->recordOffset = macLen; - gs->readOffset = macLen; - gs->writeOffset = gs->offset - gs->recordPadding; - rv = 1; - } else { - PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING); - cleanup: - /* nothing in the buffer any more. */ - gs->recordOffset = 0; - gs->readOffset = 0; - gs->writeOffset = 0; - rv = SECFailure; - } - - gs->recordLen = gs->writeOffset - gs->readOffset; - gs->recordPadding = 0; /* forget we did any padding. */ - gs->state = GS_INIT; - - if (rv > 0) { - PRINT_BUF(50, (ss, "recv clear record:", - pBuf + gs->recordOffset, gs->recordLen)); - } - return rv; - - spec_locked_done: - ssl_ReleaseSpecReadLock(ss); - return rv; - } - - case GS_DATA: - /* Have read in all the DATA portion of record */ - - gs->recordOffset = 0; - gs->readOffset = 0; - gs->writeOffset = gs->offset; - PORT_Assert(gs->recordLen == gs->writeOffset - gs->readOffset); - gs->recordLen = gs->offset; - gs->recordPadding = 0; - gs->state = GS_INIT; - - ++ss->sec.rcvSequence; - - PRINT_BUF(50, (ss, "recv clear record:", - pBuf + gs->recordOffset, gs->recordLen)); - return 1; - - } /* end switch gs->state */ - } /* end gather loop. */ - return rv; -} - -/* -** Gather a single record of data from the receiving stream. This code -** first gathers the header (2 or 3 bytes long depending on the value of -** the most significant bit in the first byte) then gathers up the data -** for the record into the readBuf. This code handles non-blocking I/O -** and is to be called multiple times until ss->sec.recordLen != 0. - * - * Returns +1 when it has gathered a complete SSLV2 record. - * Returns 0 if it hits EOF. - * Returns -1 (SECFailure) on any error - * Returns -2 (SECWouldBlock) - * - * Called by ssl_GatherRecord1stHandshake in sslcon.c, - * and by DoRecv in sslsecur.c - * Caller must hold RecvBufLock. - */ -int -ssl2_GatherRecord(sslSocket *ss, int flags) -{ - return ssl2_GatherData(ss, &ss->gs, flags); -} - -/* Caller should hold RecvBufLock. */ -SECStatus -ssl_InitGather(sslGather *gs) -{ - SECStatus status; - - gs->state = GS_INIT; - gs->writeOffset = 0; - gs->readOffset = 0; - gs->dtlsPacketOffset = 0; - gs->dtlsPacket.len = 0; - status = sslBuffer_Grow(&gs->buf, 4096); - return status; -} - -/* Caller must hold RecvBufLock. */ -void -ssl_DestroyGather(sslGather *gs) -{ - if (gs) { /* the PORT_*Free functions check for NULL pointers. */ - PORT_ZFree(gs->buf.buf, gs->buf.space); - PORT_Free(gs->inbuf.buf); - PORT_Free(gs->dtlsPacket.buf); - } -} - -/* Caller must hold RecvBufLock. */ -static SECStatus -ssl2_HandleV3HandshakeRecord(sslSocket *ss) -{ - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - - /* We've read in 3 bytes, there are 2 more to go in an ssl3 header. */ - ss->gs.remainder = 2; - ss->gs.count = 0; - - /* Clearing these handshake pointers ensures that - * ssl_Do1stHandshake won't call ssl2_HandleMessage when we return. - */ - ss->nextHandshake = 0; - ss->securityHandshake = 0; - - /* Setting ss->version to an SSL 3.x value will cause - ** ssl_GatherRecord1stHandshake to invoke ssl3_GatherCompleteHandshake() - ** the next time it is called. - **/ - rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED, - PR_TRUE); - if (rv != SECSuccess) { - return rv; - } - - ss->sec.send = ssl3_SendApplicationData; - - return SECSuccess; -}
diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h deleted file mode 100644 index f56ab53c..0000000 --- a/net/third_party/nss/ssl/sslimpl.h +++ /dev/null
@@ -1,2161 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is PRIVATE to SSL and should be the first thing included by - * any SSL implementation file. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __sslimpl_h_ -#define __sslimpl_h_ - -#ifdef DEBUG -#undef NDEBUG -#else -#undef NDEBUG -#define NDEBUG -#endif -#include "secport.h" -#include "secerr.h" -#include "sslerr.h" -#include "ssl3prot.h" -#include "hasht.h" -#include "nssilock.h" -#include "pkcs11t.h" -#if defined(XP_UNIX) || defined(XP_BEOS) -#include "unistd.h" -#endif -#include "nssrwlk.h" -#include "prthread.h" -#include "prclist.h" - -#include "sslt.h" /* for some formerly private types, now public */ - -/* to make some of these old enums public without namespace pollution, -** it was necessary to prepend ssl_ to the names. -** These #defines preserve compatibility with the old code here in libssl. -*/ -typedef SSLKEAType SSL3KEAType; -typedef SSLMACAlgorithm SSL3MACAlgorithm; - -#define calg_null ssl_calg_null -#define calg_rc4 ssl_calg_rc4 -#define calg_rc2 ssl_calg_rc2 -#define calg_des ssl_calg_des -#define calg_3des ssl_calg_3des -#define calg_idea ssl_calg_idea -#define calg_fortezza ssl_calg_fortezza /* deprecated, must preserve */ -#define calg_aes ssl_calg_aes -#define calg_camellia ssl_calg_camellia -#define calg_seed ssl_calg_seed -#define calg_aes_gcm ssl_calg_aes_gcm -#define calg_chacha20 ssl_calg_chacha20 - -#define mac_null ssl_mac_null -#define mac_md5 ssl_mac_md5 -#define mac_sha ssl_mac_sha -#define hmac_md5 ssl_hmac_md5 -#define hmac_sha ssl_hmac_sha -#define hmac_sha256 ssl_hmac_sha256 -#define mac_aead ssl_mac_aead - -#define SET_ERROR_CODE /* reminder */ -#define SEND_ALERT /* reminder */ -#define TEST_FOR_FAILURE /* reminder */ -#define DEAL_WITH_FAILURE /* reminder */ - -#if defined(DEBUG) || defined(TRACE) -#ifdef __cplusplus -#define Debug 1 -#else -extern int Debug; -#endif -#else -#undef Debug -#endif - -#if defined(DEBUG) && !defined(TRACE) && !defined(NISCC_TEST) -#define TRACE -#endif - -#ifdef TRACE -#define SSL_TRC(a, b) \ - if (ssl_trace >= (a)) \ - ssl_Trace b -#define PRINT_BUF(a, b) \ - if (ssl_trace >= (a)) \ - ssl_PrintBuf b -#define DUMP_MSG(a, b) \ - if (ssl_trace >= (a)) \ - ssl_DumpMsg b -#else -#define SSL_TRC(a, b) -#define PRINT_BUF(a, b) -#define DUMP_MSG(a, b) -#endif - -#ifdef DEBUG -#define SSL_DBG(b) \ - if (ssl_debug) \ - ssl_Trace b -#else -#define SSL_DBG(b) -#endif - -#include "private/pprthred.h" /* for PR_InMonitor() */ -#define ssl_InMonitor(m) PZ_InMonitor(m) - -#define LSB(x) ((unsigned char)((x)&0xff)) -#define MSB(x) ((unsigned char)(((unsigned)(x)) >> 8)) - -/************************************************************************/ - -typedef enum { SSLAppOpRead = 0, - SSLAppOpWrite, - SSLAppOpRDWR, - SSLAppOpPost, - SSLAppOpHeader -} SSLAppOperation; - -#define SSL_MIN_MASTER_KEY_BYTES 5 -#define SSL_MAX_MASTER_KEY_BYTES 64 - -#define SSL2_SESSIONID_BYTES 16 -#define SSL3_SESSIONID_BYTES 32 - -#define SSL_MIN_CHALLENGE_BYTES 16 -#define SSL_MAX_CHALLENGE_BYTES 32 -#define SSL_CHALLENGE_BYTES 16 - -#define SSL_CONNECTIONID_BYTES 16 - -#define SSL_MIN_CYPHER_ARG_BYTES 0 -#define SSL_MAX_CYPHER_ARG_BYTES 32 - -#define SSL_MAX_MAC_BYTES 16 - -#define SSL3_RSA_PMS_LENGTH 48 -#define SSL3_MASTER_SECRET_LENGTH 48 - -/* number of wrap mechanisms potentially used to wrap master secrets. */ -#define SSL_NUM_WRAP_MECHS 16 - -/* This makes the cert cache entry exactly 4k. */ -#define SSL_MAX_CACHED_CERT_LEN 4060 - -#define NUM_MIXERS 9 - -/* Mask of the 25 named curves we support. */ -#define SSL3_ALL_SUPPORTED_CURVES_MASK 0x3fffffe -/* Mask of only 3 curves, suite B */ -#define SSL3_SUITE_B_SUPPORTED_CURVES_MASK 0x3800000 - -#ifndef BPB -#define BPB 8 /* Bits Per Byte */ -#endif - -#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */ - -#define INITIAL_DTLS_TIMEOUT_MS 1000 /* Default value from RFC 4347 = 1s*/ -#define MAX_DTLS_TIMEOUT_MS 60000 /* 1 minute */ -#define DTLS_FINISHED_TIMER_MS 120000 /* Time to wait in FINISHED state */ - -typedef struct sslBufferStr sslBuffer; -typedef struct sslConnectInfoStr sslConnectInfo; -typedef struct sslGatherStr sslGather; -typedef struct sslSecurityInfoStr sslSecurityInfo; -typedef struct sslSessionIDStr sslSessionID; -typedef struct sslSocketStr sslSocket; -typedef struct sslSocketOpsStr sslSocketOps; - -typedef struct ssl3StateStr ssl3State; -typedef struct ssl3CertNodeStr ssl3CertNode; -typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef; -typedef struct ssl3MACDefStr ssl3MACDef; -typedef struct ssl3KeyPairStr ssl3KeyPair; -typedef struct ssl3DHParamsStr ssl3DHParams; - -struct ssl3CertNodeStr { - struct ssl3CertNodeStr *next; - CERTCertificate *cert; -}; - -typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss); - -/* This type points to the low layer send func, -** e.g. ssl2_SendStream or ssl3_SendPlainText. -** These functions return the same values as PR_Send, -** i.e. >= 0 means number of bytes sent, < 0 means error. -*/ -typedef PRInt32 (*sslSendFunc)(sslSocket *ss, const unsigned char *buf, - PRInt32 n, PRInt32 flags); - -typedef void (*sslSessionIDCacheFunc)(sslSessionID *sid); -typedef void (*sslSessionIDUncacheFunc)(sslSessionID *sid); -typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr, - unsigned char *sid, - unsigned int sidLen, - CERTCertDBHandle *dbHandle); - -/* registerable callback function that either appends extension to buffer - * or returns length of data that it would have appended. - */ -typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(sslSocket *ss, PRBool append, - PRUint32 maxBytes); - -/* registerable callback function that handles a received extension, - * of the given type. - */ -typedef SECStatus (*ssl3HelloExtensionHandlerFunc)(sslSocket *ss, - PRUint16 ex_type, - SECItem *data); - -/* row in a table of hello extension senders */ -typedef struct { - PRInt32 ex_type; - ssl3HelloExtensionSenderFunc ex_sender; -} ssl3HelloExtensionSender; - -/* row in a table of hello extension handlers */ -typedef struct { - PRInt32 ex_type; - ssl3HelloExtensionHandlerFunc ex_handler; -} ssl3HelloExtensionHandler; - -extern SECStatus -ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, - ssl3HelloExtensionSenderFunc cb); - -extern PRInt32 -ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, - const ssl3HelloExtensionSender *sender); - -extern unsigned int -ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength); - -extern PRInt32 -ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, - PRUint32 maxBytes); - -/* Socket ops */ -struct sslSocketOpsStr { - int (*connect)(sslSocket *, const PRNetAddr *); - PRFileDesc *(*accept)(sslSocket *, PRNetAddr *); - int (*bind)(sslSocket *, const PRNetAddr *); - int (*listen)(sslSocket *, int); - int (*shutdown)(sslSocket *, int); - int (*close)(sslSocket *); - - int (*recv)(sslSocket *, unsigned char *, int, int); - - /* points to the higher-layer send func, e.g. ssl_SecureSend. */ - int (*send)(sslSocket *, const unsigned char *, int, int); - int (*read)(sslSocket *, unsigned char *, int); - int (*write)(sslSocket *, const unsigned char *, int); - - int (*getpeername)(sslSocket *, PRNetAddr *); - int (*getsockname)(sslSocket *, PRNetAddr *); -}; - -/* Flags interpreted by ssl send functions. */ -#define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000 -#define ssl_SEND_FLAG_NO_BUFFER 0x20000000 -#define ssl_SEND_FLAG_USE_EPOCH 0x10000000 /* DTLS only */ -#define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */ -#define ssl_SEND_FLAG_CAP_RECORD_VERSION \ - 0x04000000 /* TLS only */ -#define ssl_SEND_FLAG_MASK 0x7f000000 - -/* -** A buffer object. -*/ -struct sslBufferStr { - unsigned char *buf; - unsigned int len; - unsigned int space; -}; - -/* -** SSL3 cipher suite policy and preference struct. -*/ -typedef struct { -#if !defined(_WIN32) - unsigned int cipher_suite : 16; - unsigned int policy : 8; - unsigned int enabled : 1; - unsigned int isPresent : 1; -#else - ssl3CipherSuite cipher_suite; - PRUint8 policy; - unsigned char enabled : 1; - unsigned char isPresent : 1; -#endif -} ssl3CipherSuiteCfg; - -#ifndef NSS_DISABLE_ECC -#define ssl_V3_SUITES_IMPLEMENTED 67 -#else -#define ssl_V3_SUITES_IMPLEMENTED 41 -#endif /* NSS_DISABLE_ECC */ - -#define MAX_DTLS_SRTP_CIPHER_SUITES 4 - -/* MAX_SIGNATURE_ALGORITHMS allows for a large number of combinations of - * SSLSignType and SSLHashType, but not all combinations (specifically, this - * doesn't allow space for combinations with MD5). */ -#define MAX_SIGNATURE_ALGORITHMS 15 - -/* clang-format off */ -typedef struct sslOptionsStr { - /* If SSL_SetNextProtoNego has been called, then this contains the - * list of supported protocols. */ - SECItem nextProtoNego; - - unsigned int useSecurity : 1; /* 1 */ - unsigned int useSocks : 1; /* 2 */ - unsigned int requestCertificate : 1; /* 3 */ - unsigned int requireCertificate : 2; /* 4-5 */ - unsigned int handshakeAsClient : 1; /* 6 */ - unsigned int handshakeAsServer : 1; /* 7 */ - unsigned int enableSSL2 : 1; /* 8 */ - unsigned int unusedBit9 : 1; /* 9 */ - unsigned int unusedBit10 : 1; /* 10 */ - unsigned int noCache : 1; /* 11 */ - unsigned int fdx : 1; /* 12 */ - unsigned int v2CompatibleHello : 1; /* 13 */ - unsigned int detectRollBack : 1; /* 14 */ - unsigned int noStepDown : 1; /* 15 */ - unsigned int bypassPKCS11 : 1; /* 16 */ - unsigned int noLocks : 1; /* 17 */ - unsigned int enableSessionTickets : 1; /* 18 */ - unsigned int enableDeflate : 1; /* 19 */ - unsigned int enableRenegotiation : 2; /* 20-21 */ - unsigned int requireSafeNegotiation : 1; /* 22 */ - unsigned int enableFalseStart : 1; /* 23 */ - unsigned int cbcRandomIV : 1; /* 24 */ - unsigned int enableOCSPStapling : 1; /* 25 */ - unsigned int enableNPN : 1; /* 26 */ - unsigned int enableALPN : 1; /* 27 */ - unsigned int reuseServerECDHEKey : 1; /* 28 */ - unsigned int enableFallbackSCSV : 1; /* 29 */ - unsigned int enableServerDhe : 1; /* 30 */ - unsigned int enableExtendedMS : 1; /* 31 */ - unsigned int enableSignedCertTimestamps : 1; /* 32 */ -} sslOptions; -/* clang-format on */ - -typedef enum { sslHandshakingUndetermined = 0, - sslHandshakingAsClient, - sslHandshakingAsServer -} sslHandshakingType; - -typedef struct sslServerCertsStr { - /* Configuration state for server sockets */ - CERTCertificate *serverCert; - CERTCertificateList *serverCertChain; - ssl3KeyPair *serverKeyPair; - unsigned int serverKeyBits; -} sslServerCerts; - -#define SERVERKEY serverKeyPair->privKey - -#define SSL_LOCK_RANK_SPEC 255 -#define SSL_LOCK_RANK_GLOBAL NSS_RWLOCK_RANK_NONE - -/* These are the valid values for shutdownHow. -** These values are each 1 greater than the NSPR values, and the code -** depends on that relation to efficiently convert PR_SHUTDOWN values -** into ssl_SHUTDOWN values. These values use one bit for read, and -** another bit for write, and can be used as bitmasks. -*/ -#define ssl_SHUTDOWN_NONE 0 /* NOT shutdown at all */ -#define ssl_SHUTDOWN_RCV 1 /* PR_SHUTDOWN_RCV +1 */ -#define ssl_SHUTDOWN_SEND 2 /* PR_SHUTDOWN_SEND +1 */ -#define ssl_SHUTDOWN_BOTH 3 /* PR_SHUTDOWN_BOTH +1 */ - -/* -** A gather object. Used to read some data until a count has been -** satisfied. Primarily for support of async sockets. -** Everything in here is protected by the recvBufLock. -*/ -struct sslGatherStr { - int state; /* see GS_ values below. */ /* ssl 2 & 3 */ - - /* "buf" holds received plaintext SSL records, after decrypt and MAC check. - * SSL2: recv'd ciphertext records are put here, then decrypted in place. - * SSL3: recv'd ciphertext records are put in inbuf (see below), then - * decrypted into buf. - */ - sslBuffer buf; /*recvBufLock*/ /* ssl 2 & 3 */ - - /* number of bytes previously read into hdr or buf(ssl2) or inbuf (ssl3). - ** (offset - writeOffset) is the number of ciphertext bytes read in but - ** not yet deciphered. - */ - unsigned int offset; /* ssl 2 & 3 */ - - /* number of bytes to read in next call to ssl_DefRecv (recv) */ - unsigned int remainder; /* ssl 2 & 3 */ - - /* Number of ciphertext bytes to read in after 2-byte SSL record header. */ - unsigned int count; /* ssl2 only */ - - /* size of the final plaintext record. - ** == count - (recordPadding + MAC size) - */ - unsigned int recordLen; /* ssl2 only */ - - /* number of bytes of padding to be removed after decrypting. */ - /* This value is taken from the record's hdr[2], which means a too large - * value could crash us. - */ - unsigned int recordPadding; /* ssl2 only */ - - /* plaintext DATA begins this many bytes into "buf". */ - unsigned int recordOffset; /* ssl2 only */ - - int encrypted; /* SSL2 session is now encrypted. ssl2 only */ - - /* These next two values are used by SSL2 and SSL3. - ** DoRecv uses them to extract application data. - ** The difference between writeOffset and readOffset is the amount of - ** data available to the application. Note that the actual offset of - ** the data in "buf" is recordOffset (above), not readOffset. - ** In the current implementation, this is made available before the - ** MAC is checked!! - */ - unsigned int readOffset; /* Spot where DATA reader (e.g. application - ** or handshake code) will read next. - ** Always zero for SSl3 application data. - */ - /* offset in buf/inbuf/hdr into which new data will be read from socket. */ - unsigned int writeOffset; - - /* Buffer for ssl3 to read (encrypted) data from the socket */ - sslBuffer inbuf; /*recvBufLock*/ /* ssl3 only */ - - /* The ssl[23]_GatherData functions read data into this buffer, rather - ** than into buf or inbuf, while in the GS_HEADER state. - ** The portion of the SSL record header put here always comes off the wire - ** as plaintext, never ciphertext. - ** For SSL2, the plaintext portion is two bytes long. For SSl3 it is 5. - ** For DTLS it is 13. - */ - unsigned char hdr[13]; /* ssl 2 & 3 or dtls */ - - /* Buffer for DTLS data read off the wire as a single datagram */ - sslBuffer dtlsPacket; - - /* the start of the buffered DTLS record in dtlsPacket */ - unsigned int dtlsPacketOffset; -}; - -/* sslGather.state */ -#define GS_INIT 0 -#define GS_HEADER 1 -#define GS_MAC 2 -#define GS_DATA 3 -#define GS_PAD 4 - -/* -** ssl3State and CipherSpec structs -*/ - -/* The SSL bulk cipher definition */ -typedef enum { - cipher_null, - cipher_rc4, - cipher_rc4_40, - cipher_rc4_56, - cipher_rc2, - cipher_rc2_40, - cipher_des, - cipher_3des, - cipher_des40, - cipher_idea, - cipher_aes_128, - cipher_aes_256, - cipher_camellia_128, - cipher_camellia_256, - cipher_seed, - cipher_aes_128_gcm, - cipher_chacha20, - cipher_missing /* reserved for no such supported cipher */ - /* This enum must match ssl3_cipherName[] in ssl3con.c. */ -} SSL3BulkCipher; - -typedef enum { type_stream, - type_block, - type_aead } CipherType; - -#define MAX_IV_LENGTH 24 - -/* - * Do not depend upon 64 bit arithmetic in the underlying machine. - */ -typedef struct { - PRUint32 high; - PRUint32 low; -} SSL3SequenceNumber; - -typedef PRUint16 DTLSEpoch; - -typedef void (*DTLSTimerCb)(sslSocket *); - -/* 400 is large enough for MD5, SHA-1, and SHA-256. - * For SHA-384 support, increase it to 712. */ -#define MAX_MAC_CONTEXT_BYTES 400 -#define MAX_MAC_CONTEXT_LLONGS (MAX_MAC_CONTEXT_BYTES / 8) - -#define MAX_CIPHER_CONTEXT_BYTES 2080 -#define MAX_CIPHER_CONTEXT_LLONGS (MAX_CIPHER_CONTEXT_BYTES / 8) - -typedef struct { - SSL3Opaque wrapped_master_secret[48]; - PRUint16 wrapped_master_secret_len; - PRUint8 msIsWrapped; - PRUint8 resumable; - PRUint8 extendedMasterSecretUsed; -} ssl3SidKeys; /* 52 bytes */ - -typedef struct { - PK11SymKey *write_key; - PK11SymKey *write_mac_key; - PK11Context *write_mac_context; - SECItem write_key_item; - SECItem write_iv_item; - SECItem write_mac_key_item; - SSL3Opaque write_iv[MAX_IV_LENGTH]; - PRUint64 cipher_context[MAX_CIPHER_CONTEXT_LLONGS]; -} ssl3KeyMaterial; - -typedef SECStatus (*SSLCipher)(void *context, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen); -typedef SECStatus (*SSLAEADCipher)( - ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen, - const unsigned char *additionalData, - int additionalDataLen); -typedef SECStatus (*SSLCompressor)(void *context, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen); -typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit); - -/* The DTLS anti-replay window. Defined here because we need it in - * the cipher spec. Note that this is a ring buffer but left and - * right represent the true window, with modular arithmetic used to - * map them onto the buffer. - */ -#define DTLS_RECVD_RECORDS_WINDOW 1024 /* Packets; approximate \ - * Must be divisible by 8 \ - */ -typedef struct DTLSRecvdRecordsStr { - unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8]; - PRUint64 left; - PRUint64 right; -} DTLSRecvdRecords; - -/* -** These are the "specs" in the "ssl3" struct. -** Access to the pointers to these specs, and all the specs' contents -** (direct and indirect) is protected by the reader/writer lock ss->specLock. -*/ -typedef struct { - const ssl3BulkCipherDef *cipher_def; - const ssl3MACDef *mac_def; - SSLCompressionMethod compression_method; - int mac_size; - SSLCipher encode; - SSLCipher decode; - SSLAEADCipher aead; - SSLDestroy destroy; - void *encodeContext; - void *decodeContext; - SSLCompressor compressor; /* Don't name these fields compress */ - SSLCompressor decompressor; /* and uncompress because zconf.h */ - /* may define them as macros. */ - SSLDestroy destroyCompressContext; - void *compressContext; - SSLDestroy destroyDecompressContext; - void *decompressContext; - PRBool bypassCiphers; /* did double bypass (at least) */ - PK11SymKey *master_secret; - SSL3SequenceNumber write_seq_num; - SSL3SequenceNumber read_seq_num; - SSL3ProtocolVersion version; - ssl3KeyMaterial client; - ssl3KeyMaterial server; - SECItem msItem; - unsigned char key_block[NUM_MIXERS * MD5_LENGTH]; - unsigned char raw_master_secret[56]; - SECItem srvVirtName; /* for server: name that was negotiated - * with a client. For client - is - * always set to NULL.*/ - DTLSEpoch epoch; - DTLSRecvdRecords recvdRecords; -} ssl3CipherSpec; - -typedef enum { never_cached, - in_client_cache, - in_server_cache, - invalid_cache /* no longer in any cache. */ -} Cached; - -#define MAX_PEER_CERT_CHAIN_SIZE 8 - -struct sslSessionIDStr { - /* The global cache lock must be held when accessing these members when the - * sid is in any cache. - */ - sslSessionID *next; /* chain used for client sockets, only */ - Cached cached; - int references; - PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */ - - /* The rest of the members, except for the members of u.ssl3.locked, may - * be modified only when the sid is not in any cache. - */ - - CERTCertificate *peerCert; - CERTCertificate *peerCertChain[MAX_PEER_CERT_CHAIN_SIZE]; - SECItemArray peerCertStatus; /* client only */ - const char *peerID; /* client only */ - const char *urlSvrName; /* client only */ - CERTCertificate *localCert; - - PRIPv6Addr addr; - PRUint16 port; - - SSL3ProtocolVersion version; - - PRUint32 creationTime; /* seconds since Jan 1, 1970 */ - PRUint32 expirationTime; /* seconds since Jan 1, 1970 */ - - SSLSignType authAlgorithm; - PRUint32 authKeyBits; - SSLKEAType keaType; - PRUint32 keaKeyBits; - - union { - struct { - /* the V2 code depends upon the size of sessionID. */ - unsigned char sessionID[SSL2_SESSIONID_BYTES]; - - /* Stuff used to recreate key and read/write cipher objects */ - SECItem masterKey; /* never wrapped */ - int cipherType; - SECItem cipherArg; - int keyBits; - int secretKeyBits; - } ssl2; - struct { - /* values that are copied into the server's on-disk SID cache. */ - PRUint8 sessionIDLength; - SSL3Opaque sessionID[SSL3_SESSIONID_BYTES]; - - ssl3CipherSuite cipherSuite; - SSLCompressionMethod compression; - int policy; - ssl3SidKeys keys; - CK_MECHANISM_TYPE masterWrapMech; - /* mechanism used to wrap master secret */ - SSL3KEAType exchKeyType; - /* key type used in exchange algorithm, - * and to wrap the sym wrapping key. */ -#ifndef NSS_DISABLE_ECC - PRUint32 negotiatedECCurves; -#endif /* NSS_DISABLE_ECC */ - - /* The following values are NOT restored from the server's on-disk - * session cache, but are restored from the client's cache. - */ - PK11SymKey *clientWriteKey; - PK11SymKey *serverWriteKey; - - /* The following values pertain to the slot that wrapped the - ** master secret. (used only in client) - */ - SECMODModuleID masterModuleID; - /* what module wrapped the master secret */ - CK_SLOT_ID masterSlotID; - PRUint16 masterWrapIndex; - /* what's the key index for the wrapping key */ - PRUint16 masterWrapSeries; - /* keep track of the slot series, so we don't - * accidently try to use new keys after the - * card gets removed and replaced.*/ - - /* The following values pertain to the slot that did the signature - ** for client auth. (used only in client) - */ - SECMODModuleID clAuthModuleID; - CK_SLOT_ID clAuthSlotID; - PRUint16 clAuthSeries; - - char masterValid; - char clAuthValid; - - SECItem srvName; - - /* originalHandshakeHash contains the hash of the original, full - * handshake prior to the server's final flow. This is either a - * SHA-1/MD5 combination (for TLS < 1.2) or the TLS PRF hash (for - * TLS 1.2). This is recorded and used only when ChannelID is - * negotiated as it's used to bind the ChannelID signature on the - * resumption handshake to the original handshake. */ - SECItem originalHandshakeHash; - - /* Signed certificate timestamps received in a TLS extension. - ** (used only in client). - */ - SECItem signedCertTimestamps; - - /* This lock is lazily initialized by CacheSID when a sid is first - * cached. Before then, there is no need to lock anything because - * the sid isn't being shared by anything. - */ - PRRWLock *lock; - - /* The lock must be held while reading or writing these members - * because they change while the sid is cached. - */ - struct { - /* The session ticket, if we have one, is sent as an extension - * in the ClientHello message. This field is used only by - * clients. It is protected by lock when lock is non-null - * (after the sid has been added to the client session cache). - */ - NewSessionTicket sessionTicket; - } locked; - } ssl3; - } u; -}; - -typedef struct ssl3CipherSuiteDefStr { - ssl3CipherSuite cipher_suite; - SSL3BulkCipher bulk_cipher_alg; - SSL3MACAlgorithm mac_alg; - SSL3KeyExchangeAlgorithm key_exchange_alg; -} ssl3CipherSuiteDef; - -/* -** There are tables of these, all const. -*/ -typedef struct { - SSL3KeyExchangeAlgorithm kea; - SSL3KEAType exchKeyType; - SSLSignType signKeyType; - /* For export cipher suites: - * is_limited identifies a suite as having a limit on the key size. - * key_size_limit provides the corresponding limit. */ - PRBool is_limited; - unsigned int key_size_limit; - PRBool tls_keygen; - /* True if the key exchange for the suite is ephemeral. Or to be more - * precise: true if the ServerKeyExchange message is always required. */ - PRBool ephemeral; - /* An OID describing the key exchange */ - SECOidTag oid; -} ssl3KEADef; - -/* -** There are tables of these, all const. -*/ -struct ssl3BulkCipherDefStr { - SSL3BulkCipher cipher; - SSLCipherAlgorithm calg; - int key_size; - int secret_key_size; - CipherType type; - int iv_size; - int block_size; - int tag_size; /* authentication tag size for AEAD ciphers. */ - int explicit_nonce_size; /* for AEAD ciphers. */ - SECOidTag oid; -}; - -/* -** There are tables of these, all const. -*/ -struct ssl3MACDefStr { - SSL3MACAlgorithm mac; - CK_MECHANISM_TYPE mmech; - int pad_size; - int mac_size; - SECOidTag oid; -}; - -typedef enum { - wait_client_hello, - wait_client_cert, - wait_client_key, - wait_cert_verify, - wait_change_cipher, - wait_finished, - wait_server_hello, - wait_certificate_status, - wait_server_cert, - wait_server_key, - wait_cert_request, - wait_hello_done, - wait_new_session_ticket, - wait_encrypted_extensions, - idle_handshake, - wait_invalid /* Invalid value. There is no handshake message "invalid". */ -} SSL3WaitState; - -/* - * TLS extension related constants and data structures. - */ -typedef struct TLSExtensionDataStr TLSExtensionData; -typedef struct SessionTicketDataStr SessionTicketData; - -struct TLSExtensionDataStr { - /* registered callbacks that send server hello extensions */ - ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS]; - ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS]; - - /* Keep track of the extensions that are negotiated. */ - PRUint16 numAdvertised; - PRUint16 numNegotiated; - PRUint16 advertised[SSL_MAX_EXTENSIONS]; - PRUint16 negotiated[SSL_MAX_EXTENSIONS]; - - /* SessionTicket Extension related data. */ - PRBool ticketTimestampVerified; - PRBool emptySessionTicket; - PRBool sentSessionTicketInClientHello; - - /* SNI Extension related data - * Names data is not coppied from the input buffer. It can not be - * used outside the scope where input buffer is defined and that - * is beyond ssl3_HandleClientHello function. */ - SECItem *sniNameArr; - PRUint32 sniNameArrSize; - - /* Signed Certificate Timestamps extracted from the TLS extension. - * (client only). - * This container holds a temporary pointer to the extension data, - * until a session structure (the sec.ci.sid of an sslSocket) is setup - * that can hold a permanent copy of the data - * (in sec.ci.sid.u.ssl3.signedCertTimestamps). - * The data pointed to by this structure is neither explicitly allocated - * nor copied: the pointer points to the handshake message buffer and is - * only valid in the scope of ssl3_HandleServerHello. - */ - SECItem signedCertTimestamps; -}; - -typedef SECStatus (*sslRestartTarget)(sslSocket *); - -/* -** A DTLS queued message (potentially to be retransmitted) -*/ -typedef struct DTLSQueuedMessageStr { - PRCList link; /* The linked list link */ - DTLSEpoch epoch; /* The epoch to use */ - SSL3ContentType type; /* The message type */ - unsigned char *data; /* The data */ - PRUint16 len; /* The data length */ -} DTLSQueuedMessage; - -typedef struct TLS13KeyShareEntryStr { - PRCList link; /* The linked list link */ - PRUint16 group; /* The group for the entry */ - SECItem key_exchange; /* The share itself */ -} TLS13KeyShareEntry; - -typedef enum { - handshake_hash_unknown = 0, - handshake_hash_combo = 1, /* The MD5/SHA-1 combination */ - handshake_hash_single = 2 /* A single hash */ -} SSL3HandshakeHashType; - -/* -** This is the "hs" member of the "ssl3" struct. -** This entire struct is protected by ssl3HandshakeLock -*/ -typedef struct SSL3HandshakeStateStr { - SSL3Random server_random; - SSL3Random client_random; - SSL3WaitState ws; /* May also contain SSL3WaitState | 0x80 for TLS 1.3 */ - - /* This group of members is used for handshake running hashes. */ - SSL3HandshakeHashType hashType; - sslBuffer messages; /* Accumulated handshake messages */ -#ifndef NO_PKCS11_BYPASS - /* Bypass mode: - * SSL 3.0 - TLS 1.1 use both |md5_cx| and |sha_cx|. |md5_cx| is used for - * MD5 and |sha_cx| for SHA-1. - * TLS 1.2 and later use only |sha_cx|, for SHA-256. NOTE: When we support - * SHA-384, increase MAX_MAC_CONTEXT_BYTES to 712. */ - PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS]; - PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; - const SECHashObject *sha_obj; - /* The function prototype of sha_obj->clone() does not match the prototype - * of the freebl <HASH>_Clone functions, so we need a dedicated function - * pointer for the <HASH>_Clone function. */ - void (*sha_clone)(void *dest, void *src); -#endif - /* PKCS #11 mode: - * SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and - * |sha| for SHA-1. - * TLS 1.2 and later use only |sha|, for SHA-256. */ - /* NOTE: On the client side, TLS 1.2 and later use |md5| as a backup - * handshake hash for generating client auth signatures. Confusingly, the - * backup hash function is SHA-1. */ -#define backupHash md5 - PK11Context *md5; - PK11Context *sha; - - const ssl3KEADef *kea_def; - ssl3CipherSuite cipher_suite; - const ssl3CipherSuiteDef *suite_def; - SSLCompressionMethod compression; - sslBuffer msg_body; /* protected by recvBufLock */ - /* partial handshake message from record layer */ - unsigned int header_bytes; - /* number of bytes consumed from handshake */ - /* message for message type and header length */ - SSL3HandshakeType msg_type; - unsigned long msg_len; - SECItem ca_list; /* used only by client */ - PRBool isResuming; /* are we resuming a session */ - PRBool usedStepDownKey; /* we did a server key exchange. */ - PRBool sendingSCSV; /* instead of empty RI */ - sslBuffer msgState; /* current state for handshake messages*/ - /* protected by recvBufLock */ - - /* The session ticket received in a NewSessionTicket message is temporarily - * stored in newSessionTicket until the handshake is finished; then it is - * moved to the sid. - */ - PRBool receivedNewSessionTicket; - NewSessionTicket newSessionTicket; - - PRUint16 finishedBytes; /* size of single finished below */ - union { - TLSFinished tFinished[2]; /* client, then server */ - SSL3Finished sFinished[2]; - SSL3Opaque data[72]; - } finishedMsgs; -#ifndef NSS_DISABLE_ECC - PRUint32 negotiatedECCurves; /* bit mask */ -#endif /* NSS_DISABLE_ECC */ - - PRBool authCertificatePending; - /* Which function should SSL_RestartHandshake* call if we're blocked? - * One of NULL, ssl3_SendClientSecondRound, ssl3_FinishHandshake, - * or ssl3_AlwaysFail */ - sslRestartTarget restartTarget; - /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */ - PRBool cacheSID; - - PRBool canFalseStart; /* Can/did we False Start */ - /* Which preliminaryinfo values have been set. */ - PRUint32 preliminaryInfo; - - /* clientSigAndHash contains the contents of the signature_algorithms - * extension (if any) from the client. This is only valid for TLS 1.2 - * or later. */ - SSLSignatureAndHashAlg *clientSigAndHash; - unsigned int numClientSigAndHash; - - /* This group of values is used for DTLS */ - PRUint16 sendMessageSeq; /* The sending message sequence - * number */ - PRCList lastMessageFlight; /* The last message flight we - * sent */ - PRUint16 maxMessageSent; /* The largest message we sent */ - PRUint16 recvMessageSeq; /* The receiving message sequence - * number */ - sslBuffer recvdFragments; /* The fragments we have received in - * a bitmask */ - PRInt32 recvdHighWater; /* The high water mark for fragments - * received. -1 means no reassembly - * in progress. */ - unsigned char cookie[32]; /* The cookie */ - unsigned char cookieLen; /* The length of the cookie */ - PRIntervalTime rtTimerStarted; /* When the timer was started */ - DTLSTimerCb rtTimerCb; /* The function to call on expiry */ - PRUint32 rtTimeoutMs; /* The length of the current timeout - * used for backoff (in ms) */ - PRUint32 rtRetries; /* The retry counter */ - - /* This group of values is used for TLS 1.3 and above */ - PRCList remoteKeyShares; /* The other side's public keys */ - PK11SymKey *xSS; /* Extracted static secret */ - PK11SymKey *xES; /* Extracted ephemeral secret */ - PK11SymKey *trafficSecret; /* The source key to use to generate - * traffic keys */ - PK11SymKey *clientFinishedSecret; /* Used for client Finished */ - PK11SymKey *serverFinishedSecret; /* Used for server Finished */ - unsigned char certReqContext[255]; /* Ties CertificateRequest - * to Certificate */ - PRUint8 certReqContextLen; /* Length of the context - * cannot be greater than 255. */ -} SSL3HandshakeState; - -/* -** This is the "ssl3" struct, as in "ss->ssl3". -** note: -** usually, crSpec == cwSpec and prSpec == pwSpec. -** Sometimes, crSpec == pwSpec and prSpec == cwSpec. -** But there are never more than 2 actual specs. -** No spec must ever be modified if either "current" pointer points to it. -*/ -struct ssl3StateStr { - - /* - ** The following Specs and Spec pointers must be protected using the - ** Spec Lock. - */ - ssl3CipherSpec *crSpec; /* current read spec. */ - ssl3CipherSpec *prSpec; /* pending read spec. */ - ssl3CipherSpec *cwSpec; /* current write spec. */ - ssl3CipherSpec *pwSpec; /* pending write spec. */ - - CERTCertificate *clientCertificate; /* used by client */ - SECKEYPrivateKey *clientPrivateKey; /* used by client */ - CERTCertificateList *clientCertChain; /* used by client */ - PRBool sendEmptyCert; /* used by client */ - - SECKEYPrivateKey *channelID; /* used by client */ - SECKEYPublicKey *channelIDPub; /* used by client */ - - int policy; - /* This says what cipher suites we can do, and should - * be either SSL_ALLOWED or SSL_RESTRICTED - */ - PLArenaPool *peerCertArena; - /* These are used to keep track of the peer CA */ - void *peerCertChain; - /* chain while we are trying to validate it. */ - CERTDistNames *ca_list; - /* used by server. trusted CAs for this socket. */ - PRBool initialized; - SSL3HandshakeState hs; - ssl3CipherSpec specs[2]; /* one is current, one is pending. */ - - /* In a client: if the server supports Next Protocol Negotiation, then - * this is the protocol that was negotiated. - */ - SECItem nextProto; - SSLNextProtoState nextProtoState; - - PRUint16 mtu; /* Our estimate of the MTU */ - - /* DTLS-SRTP cipher suite preferences (if any) */ - PRUint16 dtlsSRTPCiphers[MAX_DTLS_SRTP_CIPHER_SUITES]; - PRUint16 dtlsSRTPCipherCount; - PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */ - PRBool fatalAlertSent; - PRUint16 numDHEGroups; /* used by server */ - SSLDHEGroupType *dheGroups; /* used by server */ - PRBool dheWeakGroupEnabled; /* used by server */ - - /* TLS 1.2 introduces separate signature algorithm negotiation. - * This is our preference order. */ - SSLSignatureAndHashAlg signatureAlgorithms[MAX_SIGNATURE_ALGORITHMS]; - unsigned int signatureAlgorithmCount; - - /* The version to check if we fell back from our highest version - * of TLS. Default is 0 in which case we check against the maximum - * configured version for this socket. Used only on the client. */ - SSL3ProtocolVersion downgradeCheckVersion; -}; - -/* Ethernet MTU but without subtracting the headers, - * so slightly larger than expected */ -#define DTLS_MAX_MTU 1500U -#define IS_DTLS(ss) (ss->protocolVariant == ssl_variant_datagram) - -typedef struct { - SSL3ContentType type; - SSL3ProtocolVersion version; - SSL3SequenceNumber seq_num; /* DTLS only */ - sslBuffer *buf; -} SSL3Ciphertext; - -struct ssl3KeyPairStr { - SECKEYPrivateKey *privKey; - SECKEYPublicKey *pubKey; - PRInt32 refCount; /* use PR_Atomic calls for this. */ -}; - -struct ssl3DHParamsStr { - SECItem prime; /* p */ - SECItem base; /* g */ -}; - -typedef struct SSLWrappedSymWrappingKeyStr { - SSL3Opaque wrappedSymmetricWrappingkey[512]; - CK_MECHANISM_TYPE symWrapMechanism; - /* unwrapped symmetric wrapping key uses this mechanism */ - CK_MECHANISM_TYPE asymWrapMechanism; - /* mechanism used to wrap the SymmetricWrappingKey using - * server's public and/or private keys. */ - SSL3KEAType exchKeyType; /* type of keys used to wrap SymWrapKey*/ - PRInt32 symWrapMechIndex; - PRUint16 wrappedSymKeyLen; -} SSLWrappedSymWrappingKey; - -typedef struct SessionTicketStr { - PRUint16 ticket_version; - SSL3ProtocolVersion ssl_version; - ssl3CipherSuite cipher_suite; - SSLCompressionMethod compression_method; - SSLSignType authAlgorithm; - PRUint32 authKeyBits; - SSLKEAType keaType; - PRUint32 keaKeyBits; - /* - * exchKeyType and msWrapMech contain meaningful values only if - * ms_is_wrapped is true. - */ - PRUint8 ms_is_wrapped; - SSLKEAType exchKeyType; /* XXX(wtc): same as keaType above? */ - CK_MECHANISM_TYPE msWrapMech; - PRUint16 ms_length; - SSL3Opaque master_secret[48]; - PRBool extendedMasterSecretUsed; - ClientIdentity client_identity; - SECItem peer_cert; - PRUint32 timestamp; - SECItem srvName; /* negotiated server name */ -} SessionTicket; - -/* - * SSL2 buffers used in SSL3. - * writeBuf in the SecurityInfo maintained by sslsecur.c is used - * to hold the data just about to be passed to the kernel - * sendBuf in the ConnectInfo maintained by sslcon.c is used - * to hold handshake messages as they are accumulated - */ - -/* -** This is "ci", as in "ss->sec.ci". -** -** Protection: All the variables in here are protected by -** firstHandshakeLock AND (in ssl3) ssl3HandshakeLock -*/ -struct sslConnectInfoStr { - /* outgoing handshakes appended to this. */ - sslBuffer sendBuf; /*xmitBufLock*/ /* ssl 2 & 3 */ - - PRIPv6Addr peer; /* ssl 2 & 3 */ - unsigned short port; /* ssl 2 & 3 */ - - sslSessionID *sid; /* ssl 2 & 3 */ - - /* see CIS_HAVE defines below for the bit values in *elements. */ - char elements; /* ssl2 only */ - char requiredElements; /* ssl2 only */ - char sentElements; /* ssl2 only */ - - char sentFinished; /* ssl2 only */ - - /* Length of server challenge. Used by client when saving challenge */ - int serverChallengeLen; /* ssl2 only */ - /* type of authentication requested by server */ - unsigned char authType; /* ssl2 only */ - - /* Challenge sent by client to server in client-hello message */ - /* SSL3 gets a copy of this. See ssl3_StartHandshakeHash(). */ - unsigned char clientChallenge[SSL_MAX_CHALLENGE_BYTES]; /* ssl 2 & 3 */ - - /* Connection-id sent by server to client in server-hello message */ - unsigned char connectionID[SSL_CONNECTIONID_BYTES]; /* ssl2 only */ - - /* Challenge sent by server to client in request-certificate message */ - unsigned char serverChallenge[SSL_MAX_CHALLENGE_BYTES]; /* ssl2 only */ - - /* Information kept to handle a request-certificate message */ - unsigned char readKey[SSL_MAX_MASTER_KEY_BYTES]; /* ssl2 only */ - unsigned char writeKey[SSL_MAX_MASTER_KEY_BYTES]; /* ssl2 only */ - unsigned keySize; /* ssl2 only */ -}; - -/* bit values for ci->elements, ci->requiredElements, sentElements. */ -#define CIS_HAVE_MASTER_KEY 0x01 -#define CIS_HAVE_CERTIFICATE 0x02 -#define CIS_HAVE_FINISHED 0x04 -#define CIS_HAVE_VERIFY 0x08 - -/* Note: The entire content of this struct and whatever it points to gets - * blown away by SSL_ResetHandshake(). This is "sec" as in "ss->sec". - * - * Unless otherwise specified below, the contents of this struct are - * protected by firstHandshakeLock AND (in ssl3) ssl3HandshakeLock. - */ -struct sslSecurityInfoStr { - sslSendFunc send; /*xmitBufLock*/ /* ssl 2 & 3 */ - int isServer; /* Spec Lock?*/ /* ssl 2 & 3 */ - sslBuffer writeBuf; /*xmitBufLock*/ /* ssl 2 & 3 */ - - int cipherType; /* ssl 2 & 3 */ - int keyBits; /* ssl 2 & 3 */ - int secretKeyBits; /* ssl 2 & 3 */ - CERTCertificate *localCert; /* ssl 2 & 3 */ - CERTCertificate *peerCert; /* ssl 2 & 3 */ - SECKEYPublicKey *peerKey; /* ssl3 only */ - - SSLSignType authAlgorithm; - PRUint32 authKeyBits; - SSLKEAType keaType; - PRUint32 keaKeyBits; - - /* - ** Procs used for SID cache (nonce) management. - ** Different implementations exist for clients/servers - ** The lookup proc is only used for servers. Baloney! - */ - sslSessionIDCacheFunc cache; /* ssl 2 & 3 */ - sslSessionIDUncacheFunc uncache; /* ssl 2 & 3 */ - - /* - ** everything below here is for ssl2 only. - ** This stuff is equivalent to SSL3's "spec", and is protected by the - ** same "Spec Lock" as used for SSL3's specs. - */ - PRUint32 sendSequence; /*xmitBufLock*/ /* ssl2 only */ - PRUint32 rcvSequence; /*recvBufLock*/ /* ssl2 only */ - - /* Hash information; used for one-way-hash functions (MD2, MD5, etc.) */ - const SECHashObject *hash; /* Spec Lock */ /* ssl2 only */ - void *hashcx; /* Spec Lock */ /* ssl2 only */ - - SECItem sendSecret; /* Spec Lock */ /* ssl2 only */ - SECItem rcvSecret; /* Spec Lock */ /* ssl2 only */ - - /* Session cypher contexts; one for each direction */ - void *readcx; /* Spec Lock */ /* ssl2 only */ - void *writecx; /* Spec Lock */ /* ssl2 only */ - SSLCipher enc; /* Spec Lock */ /* ssl2 only */ - SSLCipher dec; /* Spec Lock */ /* ssl2 only */ - void (*destroy)(void *, PRBool); /* Spec Lock */ /* ssl2 only */ - - /* Blocking information for the session cypher */ - int blockShift; /* Spec Lock */ /* ssl2 only */ - int blockSize; /* Spec Lock */ /* ssl2 only */ - - /* These are used during a connection handshake */ - sslConnectInfo ci; /* ssl 2 & 3 */ -}; - -/* -** SSL Socket struct -** -** Protection: XXX -*/ -struct sslSocketStr { - PRFileDesc *fd; - - /* Pointer to operations vector for this socket */ - const sslSocketOps *ops; - - /* SSL socket options */ - sslOptions opt; - /* Enabled version range */ - SSLVersionRange vrange; - - /* State flags */ - unsigned long clientAuthRequested; - unsigned long delayDisabled; /* Nagle delay disabled */ - unsigned long firstHsDone; /* first handshake is complete. */ - unsigned long enoughFirstHsDone; /* enough of the first handshake is - * done for callbacks to be able to - * retrieve channel security - * parameters from the SSL socket. */ - unsigned long handshakeBegun; - unsigned long lastWriteBlocked; - unsigned long recvdCloseNotify; /* received SSL EOF. */ - unsigned long TCPconnected; - unsigned long appDataBuffered; - unsigned long peerRequestedProtection; /* from old renegotiation */ - - /* version of the protocol to use */ - SSL3ProtocolVersion version; - SSL3ProtocolVersion clientHelloVersion; /* version sent in client hello. */ - - sslSecurityInfo sec; /* not a pointer any more */ - - /* protected by firstHandshakeLock AND (in ssl3) ssl3HandshakeLock. */ - const char *url; /* ssl 2 & 3 */ - - sslHandshakeFunc handshake; /*firstHandshakeLock*/ - sslHandshakeFunc nextHandshake; /*firstHandshakeLock*/ - sslHandshakeFunc securityHandshake; /*firstHandshakeLock*/ - - /* the following variable is only used with socks or other proxies. */ - char *peerID; /* String uniquely identifies target server. */ - - unsigned char *cipherSpecs; - unsigned int sizeCipherSpecs; - const unsigned char *preferredCipher; - - /* TLS ClientCertificateTypes requested during HandleCertificateRequest. */ - /* Will be NULL at all other times. */ - const SECItem *requestedCertTypes; - - ssl3KeyPair *stepDownKeyPair; /* RSA step down keys */ - - const ssl3DHParams *dheParams; /* DHE param */ - ssl3KeyPair *dheKeyPair; /* DHE keys */ - - /* Callbacks */ - SSLAuthCertificate authCertificate; - void *authCertificateArg; - SSLGetClientAuthData getClientAuthData; - void *getClientAuthDataArg; - SSLSNISocketConfig sniSocketConfig; - void *sniSocketConfigArg; - SSLBadCertHandler handleBadCert; - void *badCertArg; - SSLHandshakeCallback handshakeCallback; - void *handshakeCallbackData; - SSLCanFalseStartCallback canFalseStartCallback; - void *canFalseStartCallbackData; - void *pkcs11PinArg; - SSLNextProtoCallback nextProtoCallback; - void *nextProtoArg; - - SSLClientChannelIDCallback getChannelID; - void *getChannelIDArg; - - PRIntervalTime rTimeout; /* timeout for NSPR I/O */ - PRIntervalTime wTimeout; /* timeout for NSPR I/O */ - PRIntervalTime cTimeout; /* timeout for NSPR I/O */ - - PZLock *recvLock; /* lock against multiple reader threads. */ - PZLock *sendLock; /* lock against multiple sender threads. */ - - PZMonitor *recvBufLock; /* locks low level recv buffers. */ - PZMonitor *xmitBufLock; /* locks low level xmit buffers. */ - - /* Only one thread may operate on the socket until the initial handshake - ** is complete. This Monitor ensures that. Since SSL2 handshake is - ** only done once, this is also effectively the SSL2 handshake lock. - */ - PZMonitor *firstHandshakeLock; - - /* This monitor protects the ssl3 handshake state machine data. - ** Only one thread (reader or writer) may be in the ssl3 handshake state - ** machine at any time. */ - PZMonitor *ssl3HandshakeLock; - - /* reader/writer lock, protects the secret data needed to encrypt and MAC - ** outgoing records, and to decrypt and MAC check incoming ciphertext - ** records. */ - NSSRWLock *specLock; - - /* handle to perm cert db (and implicitly to the temp cert db) used - ** with this socket. - */ - CERTCertDBHandle *dbHandle; - - PRThread *writerThread; /* thread holds SSL_LOCK_WRITER lock */ - - PRUint16 shutdownHow; /* See ssl_SHUTDOWN defines below. */ - - PRUint16 allowedByPolicy; /* copy of global policy bits. */ - PRUint16 maybeAllowedByPolicy; /* copy of global policy bits. */ - PRUint16 chosenPreference; /* SSL2 cipher preferences. */ - - sslHandshakingType handshaking; - - /* Gather object used for gathering data */ - sslGather gs; /*recvBufLock*/ - - sslBuffer saveBuf; /*xmitBufLock*/ - sslBuffer pendingBuf; /*xmitBufLock*/ - - /* Configuration state for server sockets */ - /* server cert and key for each KEA type */ - sslServerCerts serverCerts[kt_kea_size]; - /* each cert needs its own status */ - SECItemArray *certStatusArray[kt_kea_size]; - /* Serialized signed certificate timestamps to be sent to the client - ** in a TLS extension (server only). Each certificate needs its own - ** timestamps item. - */ - SECItem signedCertTimestamps[kt_kea_size]; - - ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED]; - ssl3KeyPair *ephemeralECDHKeyPair; /* for ECDHE-* handshake */ - - /* SSL3 state info. Formerly was a pointer */ - ssl3State ssl3; - - /* - * TLS extension related data. - */ - /* True when the current session is a stateless resume. */ - PRBool statelessResume; - TLSExtensionData xtnData; - - /* Whether we are doing stream or datagram mode */ - SSLProtocolVariant protocolVariant; -}; - -/* All the global data items declared here should be protected using the -** ssl_global_data_lock, which is a reader/writer lock. -*/ -extern NSSRWLock *ssl_global_data_lock; -extern char ssl_debug; -extern char ssl_trace; -extern FILE *ssl_trace_iob; -extern FILE *ssl_keylog_iob; -extern CERTDistNames *ssl3_server_ca_list; -extern PRUint32 ssl_sid_timeout; -extern PRUint32 ssl3_sid_timeout; - -extern const char *const ssl_cipherName[]; -extern const char *const ssl3_cipherName[]; - -extern sslSessionIDLookupFunc ssl_sid_lookup; -extern sslSessionIDCacheFunc ssl_sid_cache; -extern sslSessionIDUncacheFunc ssl_sid_uncache; - -/************************************************************************/ - -SEC_BEGIN_PROTOS - -/* Internal initialization and installation of the SSL error tables */ -extern SECStatus ssl_Init(void); -extern SECStatus ssl_InitializePRErrorTable(void); - -/* Implementation of ops for default (non socks, non secure) case */ -extern int ssl_DefConnect(sslSocket *ss, const PRNetAddr *addr); -extern PRFileDesc *ssl_DefAccept(sslSocket *ss, PRNetAddr *addr); -extern int ssl_DefBind(sslSocket *ss, const PRNetAddr *addr); -extern int ssl_DefListen(sslSocket *ss, int backlog); -extern int ssl_DefShutdown(sslSocket *ss, int how); -extern int ssl_DefClose(sslSocket *ss); -extern int ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags); -extern int ssl_DefSend(sslSocket *ss, const unsigned char *buf, - int len, int flags); -extern int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len); -extern int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len); -extern int ssl_DefGetpeername(sslSocket *ss, PRNetAddr *name); -extern int ssl_DefGetsockname(sslSocket *ss, PRNetAddr *name); -extern int ssl_DefGetsockopt(sslSocket *ss, PRSockOption optname, - void *optval, PRInt32 *optlen); -extern int ssl_DefSetsockopt(sslSocket *ss, PRSockOption optname, - const void *optval, PRInt32 optlen); - -/* Implementation of ops for socks only case */ -extern int ssl_SocksConnect(sslSocket *ss, const PRNetAddr *addr); -extern PRFileDesc *ssl_SocksAccept(sslSocket *ss, PRNetAddr *addr); -extern int ssl_SocksBind(sslSocket *ss, const PRNetAddr *addr); -extern int ssl_SocksListen(sslSocket *ss, int backlog); -extern int ssl_SocksGetsockname(sslSocket *ss, PRNetAddr *name); -extern int ssl_SocksRecv(sslSocket *ss, unsigned char *buf, int len, int flags); -extern int ssl_SocksSend(sslSocket *ss, const unsigned char *buf, - int len, int flags); -extern int ssl_SocksRead(sslSocket *ss, unsigned char *buf, int len); -extern int ssl_SocksWrite(sslSocket *ss, const unsigned char *buf, int len); - -/* Implementation of ops for secure only case */ -extern int ssl_SecureConnect(sslSocket *ss, const PRNetAddr *addr); -extern PRFileDesc *ssl_SecureAccept(sslSocket *ss, PRNetAddr *addr); -extern int ssl_SecureRecv(sslSocket *ss, unsigned char *buf, - int len, int flags); -extern int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, - int len, int flags); -extern int ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len); -extern int ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len); -extern int ssl_SecureShutdown(sslSocket *ss, int how); -extern int ssl_SecureClose(sslSocket *ss); - -/* Implementation of ops for secure socks case */ -extern int ssl_SecureSocksConnect(sslSocket *ss, const PRNetAddr *addr); -extern PRFileDesc *ssl_SecureSocksAccept(sslSocket *ss, PRNetAddr *addr); -extern PRFileDesc *ssl_FindTop(sslSocket *ss); - -/* Gather funcs. */ -extern sslGather *ssl_NewGather(void); -extern SECStatus ssl_InitGather(sslGather *gs); -extern void ssl_DestroyGather(sslGather *gs); -extern int ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags); -extern int ssl2_GatherRecord(sslSocket *ss, int flags); -extern SECStatus ssl_GatherRecord1stHandshake(sslSocket *ss); - -extern SECStatus ssl2_HandleClientHelloMessage(sslSocket *ss); -extern SECStatus ssl2_HandleServerHelloMessage(sslSocket *ss); - -extern SECStatus ssl_CreateSecurityInfo(sslSocket *ss); -extern SECStatus ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os); -extern void ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset); -extern void ssl_DestroySecurityInfo(sslSecurityInfo *sec); - -extern void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *cp, int len); -extern void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len); - -extern int ssl_SendSavedWriteData(sslSocket *ss); -extern SECStatus ssl_SaveWriteData(sslSocket *ss, - const void *p, unsigned int l); -extern SECStatus ssl2_BeginClientHandshake(sslSocket *ss); -extern SECStatus ssl2_BeginServerHandshake(sslSocket *ss); -extern int ssl_Do1stHandshake(sslSocket *ss); - -extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen); -extern SECStatus sslBuffer_Append(sslBuffer *b, const void *data, - unsigned int len); - -extern void ssl2_UseClearSendFunc(sslSocket *ss); -extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec); - -extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server); -extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, - const char *peerID, const char *urlSvrName); -extern void ssl_FreeSID(sslSessionID *sid); - -extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in, - int len, int flags); - -extern PRBool ssl_FdIsBlocking(PRFileDesc *fd); - -extern PRBool ssl_SocketIsBlocking(sslSocket *ss); - -extern void ssl3_SetAlwaysBlock(sslSocket *ss); - -extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled); - -extern void ssl_FinishHandshake(sslSocket *ss); - -extern SECStatus ssl_CipherPolicySet(PRInt32 which, PRInt32 policy); - -extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled); - -extern SECStatus ssl3_ConstrainRangeByPolicy(void); - -/* Returns PR_TRUE if we are still waiting for the server to complete its - * response to our client second round. Once we've received the Finished from - * the server then there is no need to check false start. - */ -extern PRBool ssl3_WaitingForServerSecondRound(sslSocket *ss); - -extern SECStatus -ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, - PRBool isServer, - PRBool isDTLS, - PRBool capRecordVersion, - SSL3ContentType type, - const SSL3Opaque *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf); - -extern PRInt32 ssl3_SendRecord(sslSocket *ss, DTLSEpoch epoch, - SSL3ContentType type, - const SSL3Opaque *pIn, PRInt32 nIn, - PRInt32 flags); - -#ifdef NSS_SSL_ENABLE_ZLIB -/* - * The DEFLATE algorithm can result in an expansion of 0.1% + 12 bytes. For a - * maximum TLS record payload of 2**14 bytes, that's 29 bytes. - */ -#define SSL3_COMPRESSION_MAX_EXPANSION 29 -#else /* !NSS_SSL_ENABLE_ZLIB */ -#define SSL3_COMPRESSION_MAX_EXPANSION 0 -#endif - -/* - * make sure there is room in the write buffer for padding and - * other compression and cryptographic expansions. - */ -#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION - -#define SSL_LOCK_READER(ss) \ - if (ss->recvLock) \ - PZ_Lock(ss->recvLock) -#define SSL_UNLOCK_READER(ss) \ - if (ss->recvLock) \ - PZ_Unlock(ss->recvLock) -#define SSL_LOCK_WRITER(ss) \ - if (ss->sendLock) \ - PZ_Lock(ss->sendLock) -#define SSL_UNLOCK_WRITER(ss) \ - if (ss->sendLock) \ - PZ_Unlock(ss->sendLock) - -/* firstHandshakeLock -> recvBufLock */ -#define ssl_Get1stHandshakeLock(ss) \ - { \ - if (!ss->opt.noLocks) { \ - PORT_Assert(PZ_InMonitor((ss)->firstHandshakeLock) || \ - !ssl_HaveRecvBufLock(ss)); \ - PZ_EnterMonitor((ss)->firstHandshakeLock); \ - } \ - } -#define ssl_Release1stHandshakeLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - PZ_ExitMonitor((ss)->firstHandshakeLock); \ - } -#define ssl_Have1stHandshakeLock(ss) \ - (PZ_InMonitor((ss)->firstHandshakeLock)) - -/* ssl3HandshakeLock -> xmitBufLock */ -#define ssl_GetSSL3HandshakeLock(ss) \ - { \ - if (!ss->opt.noLocks) { \ - PORT_Assert(!ssl_HaveXmitBufLock(ss)); \ - PZ_EnterMonitor((ss)->ssl3HandshakeLock); \ - } \ - } -#define ssl_ReleaseSSL3HandshakeLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - PZ_ExitMonitor((ss)->ssl3HandshakeLock); \ - } -#define ssl_HaveSSL3HandshakeLock(ss) \ - (PZ_InMonitor((ss)->ssl3HandshakeLock)) - -#define ssl_GetSpecReadLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - NSSRWLock_LockRead((ss)->specLock); \ - } -#define ssl_ReleaseSpecReadLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - NSSRWLock_UnlockRead((ss)->specLock); \ - } -/* NSSRWLock_HaveReadLock is not exported so there's no - * ssl_HaveSpecReadLock macro. */ - -#define ssl_GetSpecWriteLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - NSSRWLock_LockWrite((ss)->specLock); \ - } -#define ssl_ReleaseSpecWriteLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - NSSRWLock_UnlockWrite((ss)->specLock); \ - } -#define ssl_HaveSpecWriteLock(ss) \ - (NSSRWLock_HaveWriteLock((ss)->specLock)) - -/* recvBufLock -> ssl3HandshakeLock -> xmitBufLock */ -#define ssl_GetRecvBufLock(ss) \ - { \ - if (!ss->opt.noLocks) { \ - PORT_Assert(!ssl_HaveSSL3HandshakeLock(ss)); \ - PORT_Assert(!ssl_HaveXmitBufLock(ss)); \ - PZ_EnterMonitor((ss)->recvBufLock); \ - } \ - } -#define ssl_ReleaseRecvBufLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - PZ_ExitMonitor((ss)->recvBufLock); \ - } -#define ssl_HaveRecvBufLock(ss) \ - (PZ_InMonitor((ss)->recvBufLock)) - -/* xmitBufLock -> specLock */ -#define ssl_GetXmitBufLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - PZ_EnterMonitor((ss)->xmitBufLock); \ - } -#define ssl_ReleaseXmitBufLock(ss) \ - { \ - if (!ss->opt.noLocks) \ - PZ_ExitMonitor((ss)->xmitBufLock); \ - } -#define ssl_HaveXmitBufLock(ss) \ - (PZ_InMonitor((ss)->xmitBufLock)) - -/* Placeholder value used in version ranges when SSL 3.0 and all - * versions of TLS are disabled. - */ -#define SSL_LIBRARY_VERSION_NONE 0 - -/* SSL_LIBRARY_VERSION_MAX_SUPPORTED is the maximum version that this version - * of libssl supports. Applications should use SSL_VersionRangeGetSupported at - * runtime to determine which versions are supported by the version of libssl - * in use. - */ -#ifdef NSS_ENABLE_TLS_1_3 -#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_3 -#else -#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_2 -#endif - -/* Rename this macro SSL_ALL_VERSIONS_DISABLED when SSL 2.0 is removed. */ -#define SSL3_ALL_VERSIONS_DISABLED(vrange) \ - ((vrange)->min == SSL_LIBRARY_VERSION_NONE) - -extern PRBool ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant, - SSL3ProtocolVersion version); - -extern SECStatus ssl3_KeyAndMacDeriveBypass(ssl3CipherSpec *pwSpec, - const unsigned char *cr, const unsigned char *sr, - PRBool isTLS, PRBool isExport); -extern SECStatus ssl3_MasterSecretDeriveBypass(ssl3CipherSpec *pwSpec, - const unsigned char *cr, const unsigned char *sr, - const SECItem *pms, PRBool isTLS, PRBool isRSA); - -/* These functions are called from secnav, even though they're "private". */ - -extern int ssl2_SendErrorMessage(struct sslSocketStr *ss, int error); -extern sslSocket *ssl_FindSocket(PRFileDesc *fd); -extern void ssl_FreeSocket(struct sslSocketStr *ssl); -extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, - SSL3AlertDescription desc); -extern SECStatus ssl3_DecodeError(sslSocket *ss); - -extern SECStatus ssl3_RestartHandshakeAfterCertReq(struct sslSocketStr *ss, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain); - -extern SECStatus ssl3_RestartHandshakeAfterChannelIDReq( - sslSocket *ss, - SECKEYPublicKey *channelIDPub, - SECKEYPrivateKey *channelID); - -extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error); - -/* - * for dealing with SSL 3.0 clients sending SSL 2.0 format hellos - */ -extern SECStatus ssl3_HandleV2ClientHello( - sslSocket *ss, unsigned char *buffer, int length); -extern SECStatus ssl3_StartHandshakeHash( - sslSocket *ss, unsigned char *buf, int length); - -/* - * SSL3 specific routines - */ -SECStatus ssl3_SendClientHello(sslSocket *ss, PRBool resending); - -/* - * input into the SSL3 machinery from the actualy network reading code - */ -SECStatus ssl3_HandleRecord( - sslSocket *ss, SSL3Ciphertext *cipher, sslBuffer *out); - -int ssl3_GatherAppDataRecord(sslSocket *ss, int flags); -int ssl3_GatherCompleteHandshake(sslSocket *ss, int flags); -/* - * When talking to export clients or using export cipher suites, servers - * with public RSA keys larger than 512 bits need to use a 512-bit public - * key, signed by the larger key. The smaller key is a "step down" key. - * Generate that key pair and keep it around. - */ -extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss); - -extern SECStatus ssl3_SelectDHParams(sslSocket *ss); - -#ifndef NSS_DISABLE_ECC -extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss); -extern PRBool ssl3_IsECCEnabled(sslSocket *ss); -extern SECStatus ssl3_DisableECCSuites(sslSocket *ss, - const ssl3CipherSuite *suite); -extern PRUint32 ssl3_GetSupportedECCurveMask(sslSocket *ss); - -/* Macro for finding a curve equivalent in strength to RSA key's */ -/* clang-format off */ -#define SSL_RSASTRENGTH_TO_ECSTRENGTH(s) \ - ((s <= 1024) ? 160 \ - : ((s <= 2048) ? 224 \ - : ((s <= 3072) ? 256 \ - : ((s <= 7168) ? 384 \ - : 521 ) ) ) ) -/* clang-format on */ - -/* Types and names of elliptic curves used in TLS */ -typedef enum { ec_type_explicitPrime = 1, - ec_type_explicitChar2Curve = 2, - ec_type_named -} ECType; - -typedef enum { ec_noName = 0, - ec_sect163k1 = 1, - ec_sect163r1 = 2, - ec_sect163r2 = 3, - ec_sect193r1 = 4, - ec_sect193r2 = 5, - ec_sect233k1 = 6, - ec_sect233r1 = 7, - ec_sect239k1 = 8, - ec_sect283k1 = 9, - ec_sect283r1 = 10, - ec_sect409k1 = 11, - ec_sect409r1 = 12, - ec_sect571k1 = 13, - ec_sect571r1 = 14, - ec_secp160k1 = 15, - ec_secp160r1 = 16, - ec_secp160r2 = 17, - ec_secp192k1 = 18, - ec_secp192r1 = 19, - ec_secp224k1 = 20, - ec_secp224r1 = 21, - ec_secp256k1 = 22, - ec_secp256r1 = 23, - ec_secp384r1 = 24, - ec_secp521r1 = 25, - ec_pastLastName -} ECName; - -extern SECStatus ssl3_ECName2Params(PLArenaPool *arena, ECName curve, - SECKEYECParams *params); -ECName ssl3_PubKey2ECName(SECKEYPublicKey *pubKey); - -ECName ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits); -ECName ssl3_GetCurveNameForServerSocket(sslSocket *ss); - -#endif /* NSS_DISABLE_ECC */ - -extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on); -extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on); -extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled); -extern SECStatus ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled); - -extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool on); -extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on); -extern SECStatus ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled); -extern SECStatus ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled); -extern SECStatus ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *cipher, - unsigned int len); - -extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy); -extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy); -extern SECStatus ssl2_SetPolicy(PRInt32 which, PRInt32 policy); -extern SECStatus ssl2_GetPolicy(PRInt32 which, PRInt32 *policy); - -extern void ssl2_InitSocketPolicy(sslSocket *ss); -extern void ssl3_InitSocketPolicy(sslSocket *ss); - -extern SECStatus ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, - unsigned char *cs, int *size); - -extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache); -extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, - PRUint32 length); - -extern void ssl3_DestroySSL3Info(sslSocket *ss); - -extern SECStatus ssl3_NegotiateVersion(sslSocket *ss, - SSL3ProtocolVersion peerVersion, - PRBool allowLargerPeerVersion); - -extern SECStatus ssl_GetPeerInfo(sslSocket *ss); - -#ifndef NSS_DISABLE_ECC -/* ECDH functions */ -extern SECStatus ssl3_SendECDHClientKeyExchange(sslSocket *ss, - SECKEYPublicKey *svrPubKey); -extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss, - SSL3Opaque *b, PRUint32 length); -extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, - SSL3Opaque *b, PRUint32 length, - SECKEYPublicKey *srvrPubKey, - SECKEYPrivateKey *srvrPrivKey); -extern SECStatus ssl3_SendECDHServerKeyExchange( - sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash); -SECKEYPublicKey *tls13_ImportECDHKeyShare( - sslSocket *ss, SSL3Opaque *b, PRUint32 length, ECName curve); -ECName tls13_GroupForECDHEKeyShare(ssl3KeyPair *pair); -unsigned int tls13_SizeOfECDHEKeyShareKEX(ssl3KeyPair *pair); -SECStatus tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, ssl3KeyPair *pair); -#endif - -extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg, - PRUint8 *hashBuf, - unsigned int bufLen, SSL3Hashes *hashes, - PRBool bypassPKCS11); -extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName); -extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms); -extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src, - PRInt32 bytes); -extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, - SSL3HandshakeType t, PRUint32 length); -extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, - PRInt32 lenSize); -extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss, - const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); -extern SECStatus ssl3_AppendSignatureAndHashAlgorithm( - sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash); -extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length); -extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length); -extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, - PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); -extern PRBool ssl3_IsSupportedSignatureAlgorithm( - const SSLSignatureAndHashAlg *alg); -extern SECStatus ssl3_CheckSignatureAndHashAlgorithmConsistency( - sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash, - CERTCertificate *cert); -extern SECStatus ssl3_ConsumeSignatureAndHashAlgorithm( - sslSocket *ss, SSL3Opaque **b, PRUint32 *length, - SSLSignatureAndHashAlg *out); -extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, - SECItem *buf, PRBool isTLS); -extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, - CERTCertificate *cert, SECItem *buf, PRBool isTLS, - void *pwArg); -extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss, - sslSessionID *sid, ssl3CipherSpec *spec, - SSL3KEAType effectiveExchKeyType); - -/* Functions that handle ClientHello and ServerHello extensions. */ -extern SECStatus ssl3_HandleServerNameXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -extern SECStatus ssl3_HandleSupportedCurvesXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -extern SECStatus ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); -extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, - PRUint16 ex_type, SECItem *data); - -/* ClientHello and ServerHello extension senders. - * Note that not all extension senders are exposed here; only those that - * that need exposure. - */ -extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); - -/* ClientHello and ServerHello extension senders. - * The code is in ssl3ext.c. - */ -extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); - -/* Assigns new cert, cert chain and keys to ss->serverCerts - * struct. If certChain is NULL, tries to find one. Aborts if - * fails to do so. If cert and keyPair are NULL - unconfigures - * sslSocket of kea type.*/ -extern SECStatus ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert, - const CERTCertificateList *certChain, - ssl3KeyPair *keyPair, SSLKEAType kea); - -#ifndef NSS_DISABLE_ECC -extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss, - PRBool append, PRUint32 maxBytes); -extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss, - PRBool append, PRUint32 maxBytes); -#endif - -/* call the registered extension handlers. */ -extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, - SSL3Opaque **b, PRUint32 *length, - SSL3HandshakeType handshakeMessage); - -/* Hello Extension related routines. */ -extern PRBool ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type); -extern void ssl3_SetSIDSessionTicket(sslSessionID *sid, - /*in/out*/ NewSessionTicket *session_ticket); -extern SECStatus ssl3_SendNewSessionTicket(sslSocket *ss); -extern PRBool ssl_GetSessionTicketKeys(unsigned char *keyName, - unsigned char *encKey, unsigned char *macKey); -extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, - SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey); - -/* Tell clients to consider tickets valid for this long. */ -#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */ -#define TLS_EX_SESS_TICKET_VERSION (0x0101) - -extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data, - unsigned int length); - -extern SECStatus ssl3_GetTLSUniqueChannelBinding(sslSocket *ss, - unsigned char *out, - unsigned int *outLen, - unsigned int outLenMax); - -/* Construct a new NSPR socket for the app to use */ -extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd); -extern void ssl_FreePRSocket(PRFileDesc *fd); - -/* Internal config function so SSL3 can initialize the present state of - * various ciphers */ -extern int ssl3_config_match_init(sslSocket *); - -/* Create a new ref counted key pair object from two keys. */ -extern ssl3KeyPair *ssl3_NewKeyPair(SECKEYPrivateKey *privKey, - SECKEYPublicKey *pubKey); - -/* get a new reference (bump ref count) to an ssl3KeyPair. */ -extern ssl3KeyPair *ssl3_GetKeyPairRef(ssl3KeyPair *keyPair); - -/* Decrement keypair's ref count and free if zero. */ -extern void ssl3_FreeKeyPair(ssl3KeyPair *keyPair); - -/* calls for accessing wrapping keys across processes. */ -extern PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk); - -/* The caller passes in the new value it wants - * to set. This code tests the wrapped sym key entry in the file on disk. - * If it is uninitialized, this function writes the caller's value into - * the disk entry, and returns false. - * Otherwise, it overwrites the caller's wswk with the value obtained from - * the disk, and returns PR_TRUE. - * This is all done while holding the locks/semaphores necessary to make - * the operation atomic. - */ -extern PRBool -ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk); - -/* get rid of the symmetric wrapping key references. */ -extern SECStatus SSL3_ShutdownServerCache(void); - -extern SECStatus ssl_InitSymWrapKeysLock(void); - -extern SECStatus ssl_FreeSymWrapKeysLock(void); - -extern SECStatus ssl_InitSessionCacheLocks(void); - -/**************** DTLS-specific functions **************/ -extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg); -extern void dtls_FreeQueuedMessages(PRCList *lst); -extern void dtls_FreeHandshakeMessages(PRCList *lst); - -extern SECStatus dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf); -extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss, - SSL3Opaque *b, PRUint32 length); -extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss); -extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, - const SSL3Opaque *pIn, PRInt32 nIn); -extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); -extern SECStatus dtls_CompressMACEncryptRecord(sslSocket *ss, - DTLSEpoch epoch, - PRBool use_epoch, - SSL3ContentType type, - const SSL3Opaque *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf); -SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss); -extern SECStatus dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb); -extern SECStatus dtls_RestartTimer(sslSocket *ss, PRBool backoff, - DTLSTimerCb cb); -extern void dtls_CheckTimer(sslSocket *ss); -extern void dtls_CancelTimer(sslSocket *ss); -extern void dtls_FinishedTimerCb(sslSocket *ss); -extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised); -extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records); -extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq); -extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq); -extern void dtls_RehandshakeCleanup(sslSocket *ss); -extern SSL3ProtocolVersion -dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv); -extern SSL3ProtocolVersion -dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv); -extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec, - const SSL3Ciphertext *cText, PRUint64 *seqNum); - -CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg); -SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss); -SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags); -SECStatus ssl3_SendCertificate(sslSocket *ss); -SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss, - SSL3Opaque *b, PRUint32 length); -SECStatus ssl3_SendEmptyCertificate(sslSocket *ss); -SECStatus ssl3_SendCertificateStatus(sslSocket *ss); -SECStatus ssl3_CompleteHandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, - PRUint32 length); -SECStatus ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf, - unsigned maxLen, PRUint32 *len); -void ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calenp, SECItem **namesp, - int *nnamesp); -SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, - PRUint32 *length, PLArenaPool *arena, - CERTDistNames *ca_list); -SECStatus ssl3_CompleteHandleCertificateRequest(sslSocket *ss, - SECItem *algorithms, - CERTDistNames *ca_list); -SECStatus ssl3_SendCertificateVerify(sslSocket *ss, - SECKEYPrivateKey *privKey); -SECStatus ssl3_SendServerHello(sslSocket *ss); -SECOidTag ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc); -SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss, - ssl3CipherSpec *spec, - SSL3Hashes *hashes, - PRUint32 sender); -void ssl3_BumpSequenceNumber(SSL3SequenceNumber *num); -PRInt32 tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append, - PRUint32 maxBytes); -#ifndef NSS_DISABLE_ECC -SECStatus ssl3_CreateECDHEphemeralKeyPair(ECName ec_curve, - ssl3KeyPair **keyPair); -PK11SymKey *tls13_ComputeECDHSharedKey(sslSocket *ss, - SECKEYPrivateKey *myPrivKey, - SECKEYPublicKey *peerKey); -#endif - -/* Pull in TLS 1.3 functions */ -#include "tls13con.h" - -/********************** misc calls *********************/ - -#ifdef DEBUG -extern void ssl3_CheckCipherSuiteOrderConsistency(); -#endif - -extern int ssl_MapLowLevelError(int hiLevelError); - -extern PRUint32 ssl_Time(void); - -extern void SSL_AtomicIncrementLong(long *x); - -SECStatus SSL_DisableDefaultExportCipherSuites(void); -SECStatus SSL_DisableExportCipherSuites(PRFileDesc *fd); -PRBool SSL_IsExportCipherSuite(PRUint16 cipherSuite); - -SECStatus ssl3_ApplyNSSPolicy(void); - -extern SECStatus -ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, - const char *label, unsigned int labelLen, - const unsigned char *val, unsigned int valLen, - unsigned char *out, unsigned int outLen); -extern SECOidTag -ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc); - -#ifdef TRACE -#define SSL_TRACE(msg) ssl_Trace msg -#else -#define SSL_TRACE(msg) -#endif - -void ssl_Trace(const char *format, ...); - -SEC_END_PROTOS - -#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) -#define SSL_GETPID getpid -#elif defined(WIN32) -extern int __cdecl _getpid(void); -#define SSL_GETPID _getpid -#else -#define SSL_GETPID() 0 -#endif - -#endif /* __sslimpl_h_ */
diff --git a/net/third_party/nss/ssl/sslinfo.c b/net/third_party/nss/ssl/sslinfo.c deleted file mode 100644 index c59879c..0000000 --- a/net/third_party/nss/ssl/sslinfo.c +++ /dev/null
@@ -1,460 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" - -static const char * -ssl_GetCompressionMethodName(SSLCompressionMethod compression) -{ - switch (compression) { - case ssl_compression_null: - return "NULL"; -#ifdef NSS_ENABLE_ZLIB - case ssl_compression_deflate: - return "DEFLATE"; -#endif - default: - return "???"; - } -} - -SECStatus -SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) -{ - sslSocket *ss; - SSLChannelInfo inf; - sslSessionID *sid; - - /* Check if we can properly return the length of data written and that - * we're not asked to return more information than we know how to provide. - */ - if (!info || len < sizeof inf.length || len > sizeof inf) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo", - SSL_GETPID(), fd)); - return SECFailure; - } - - memset(&inf, 0, sizeof inf); - inf.length = PR_MIN(sizeof inf, len); - - if (ss->opt.useSecurity && ss->enoughFirstHsDone) { - sid = ss->sec.ci.sid; - inf.protocolVersion = ss->version; - inf.authKeyBits = ss->sec.authKeyBits; - inf.keaKeyBits = ss->sec.keaKeyBits; - if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */ - inf.cipherSuite = ss->sec.cipherType | 0xff00; - inf.compressionMethod = ssl_compression_null; - inf.compressionMethodName = "N/A"; - } else if (ss->ssl3.initialized) { /* SSL3 and TLS */ - ssl_GetSpecReadLock(ss); - /* XXX The cipher suite should be in the specs and this - * function should get it from cwSpec rather than from the "hs". - * See bug 275744 comment 69 and bug 766137. - */ - inf.cipherSuite = ss->ssl3.hs.cipher_suite; - inf.compressionMethod = ss->ssl3.cwSpec->compression_method; - ssl_ReleaseSpecReadLock(ss); - inf.compressionMethodName = - ssl_GetCompressionMethodName(inf.compressionMethod); - } - if (sid) { - inf.creationTime = sid->creationTime; - inf.lastAccessTime = sid->lastAccessTime; - inf.expirationTime = sid->expirationTime; - inf.extendedMasterSecretUsed = - (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 || - sid->u.ssl3.keys.extendedMasterSecretUsed) - ? PR_TRUE - : PR_FALSE; - - if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */ - inf.sessionIDLength = SSL2_SESSIONID_BYTES; - memcpy(inf.sessionID, sid->u.ssl2.sessionID, - SSL2_SESSIONID_BYTES); - } else { - unsigned int sidLen = sid->u.ssl3.sessionIDLength; - sidLen = PR_MIN(sidLen, sizeof inf.sessionID); - inf.sessionIDLength = sidLen; - memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen); - } - } - } - - memcpy(info, &inf, inf.length); - - return SECSuccess; -} - -SECStatus -SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, - SSLPreliminaryChannelInfo *info, - PRUintn len) -{ - sslSocket *ss; - SSLPreliminaryChannelInfo inf; - - /* Check if we can properly return the length of data written and that - * we're not asked to return more information than we know how to provide. - */ - if (!info || len < sizeof inf.length || len > sizeof inf) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetPreliminaryChannelInfo", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (ss->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION); - return SECFailure; - } - - memset(&inf, 0, sizeof(inf)); - inf.length = PR_MIN(sizeof(inf), len); - - inf.valuesSet = ss->ssl3.hs.preliminaryInfo; - inf.protocolVersion = ss->version; - inf.cipherSuite = ss->ssl3.hs.cipher_suite; - - memcpy(info, &inf, inf.length); - return SECSuccess; -} - -#define CS(x) x, #x -#define CK(x) x | 0xff00, #x - -#define S_DSA "DSA", ssl_auth_dsa -#define S_RSA "RSA", ssl_auth_rsa -#define S_KEA "KEA", ssl_auth_kea -#define S_ECDSA "ECDSA", ssl_auth_ecdsa - -#define K_DHE "DHE", kt_dh -#define K_RSA "RSA", kt_rsa -#define K_KEA "KEA", kt_kea -#define K_ECDH "ECDH", kt_ecdh -#define K_ECDHE "ECDHE", kt_ecdh - -#define C_SEED "SEED", calg_seed -#define C_CAMELLIA "CAMELLIA", calg_camellia -#define C_AES "AES", calg_aes -#define C_RC4 "RC4", calg_rc4 -#define C_RC2 "RC2", calg_rc2 -#define C_DES "DES", calg_des -#define C_3DES "3DES", calg_3des -#define C_NULL "NULL", calg_null -#define C_SJ "SKIPJACK", calg_sj -#define C_AESGCM "AES-GCM", calg_aes_gcm -#define C_CHACHA20 "CHACHA20POLY1305", calg_chacha20 - -#define B_256 256, 256, 256 -#define B_128 128, 128, 128 -#define B_3DES 192, 156, 112 -#define B_SJ 96, 80, 80 -#define B_DES 64, 56, 56 -#define B_56 128, 56, 56 -#define B_40 128, 40, 40 -#define B_0 0, 0, 0 - -#define M_AEAD_128 "AEAD", ssl_mac_aead, 128 -#define M_SHA256 "SHA256", ssl_hmac_sha256, 256 -#define M_SHA "SHA1", ssl_mac_sha, 160 -#define M_MD5 "MD5", ssl_mac_md5, 128 -#define M_NULL "NULL", ssl_mac_null, 0 - -/* clang-format off */ -static const SSLCipherSuiteInfo suiteInfo[] = { - /* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */ - {0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 }, - {0,CS(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 }, - - {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 }, - {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 }, - {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, 1, 0, 0 }, - - {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 }, - {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED,B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0 }, - {0,CS(TLS_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, 1, 0, 0 }, - - {0,CS(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0 }, - {0,CS(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 1 }, - {0,CS(TLS_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 0 }, - - {0,CS(TLS_DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0 }, - {0,CS(TLS_DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0 }, - {0,CS(SSL_RSA_FIPS_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 1 }, - {0,CS(TLS_RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 0 }, - - {0,CS(TLS_RSA_EXPORT1024_WITH_RC4_56_SHA), S_RSA, K_RSA, C_RC4, B_56, M_SHA, 0, 1, 0 }, - {0,CS(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 1, 0 }, - {0,CS(TLS_RSA_EXPORT_WITH_RC4_40_MD5), S_RSA, K_RSA, C_RC4, B_40, M_MD5, 0, 1, 0 }, - {0,CS(TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5), S_RSA, K_RSA, C_RC2, B_40, M_MD5, 0, 1, 0 }, - {0,CS(TLS_RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL,B_0, M_SHA256, 0, 1, 0 }, - {0,CS(TLS_RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL,B_0, M_SHA, 0, 1, 0 }, - {0,CS(TLS_RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL,B_0, M_MD5, 0, 1, 0 }, - - #ifndef NSS_DISABLE_ECC - /* ECC cipher suites */ - {0,CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 }, - - {0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0 }, - - {0,CS(TLS_ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 }, - - {0,CS(TLS_ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0 }, - - {0,CS(TLS_ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0 }, - {0,CS(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0 }, - {0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0 }, - {0,CS(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 }, - #endif /* NSS_DISABLE_ECC */ - - /* SSL 2 table */ - {0,CK(SSL_CK_RC4_128_WITH_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0 }, - {0,CK(SSL_CK_RC2_128_CBC_WITH_MD5), S_RSA, K_RSA, C_RC2, B_128, M_MD5, 0, 0, 0 }, - {0,CK(SSL_CK_DES_192_EDE3_CBC_WITH_MD5), S_RSA, K_RSA, C_3DES,B_3DES,M_MD5, 0, 0, 0 }, - {0,CK(SSL_CK_DES_64_CBC_WITH_MD5), S_RSA, K_RSA, C_DES, B_DES, M_MD5, 0, 0, 0 }, - {0,CK(SSL_CK_RC4_128_EXPORT40_WITH_MD5), S_RSA, K_RSA, C_RC4, B_40, M_MD5, 0, 1, 0 }, - {0,CK(SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5), S_RSA, K_RSA, C_RC2, B_40, M_MD5, 0, 1, 0 } -}; -/* clang-format on */ - -#define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0])) - -SECStatus -SSL_GetCipherSuiteInfo(PRUint16 cipherSuite, - SSLCipherSuiteInfo *info, PRUintn len) -{ - unsigned int i; - - /* Check if we can properly return the length of data written and that - * we're not asked to return more information than we know how to provide. - */ - if (!info || len < sizeof suiteInfo[0].length || - len > sizeof suiteInfo[0]) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - len = PR_MIN(len, sizeof suiteInfo[0]); - for (i = 0; i < NUM_SUITEINFOS; i++) { - if (suiteInfo[i].cipherSuite == cipherSuite) { - memcpy(info, &suiteInfo[i], len); - info->length = len; - return SECSuccess; - } - } - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; -} - -/* This function might be a candidate to be public. - * Disables all export ciphers in the default set of enabled ciphers. - */ -SECStatus -SSL_DisableDefaultExportCipherSuites(void) -{ - const SSLCipherSuiteInfo *pInfo = suiteInfo; - unsigned int i; - - for (i = 0; i < NUM_SUITEINFOS; ++i, ++pInfo) { - if (pInfo->isExportable) { - PORT_CheckSuccess(SSL_CipherPrefSetDefault(pInfo->cipherSuite, PR_FALSE)); - } - } - return SECSuccess; -} - -/* This function might be a candidate to be public, - * except that it takes an sslSocket pointer as an argument. - * A Public version would take a PRFileDesc pointer. - * Disables all export ciphers in the default set of enabled ciphers. - */ -SECStatus -SSL_DisableExportCipherSuites(PRFileDesc *fd) -{ - const SSLCipherSuiteInfo *pInfo = suiteInfo; - unsigned int i; - - for (i = 0; i < NUM_SUITEINFOS; ++i, ++pInfo) { - if (pInfo->isExportable) { - PORT_CheckSuccess(SSL_CipherPrefSet(fd, pInfo->cipherSuite, PR_FALSE)); - } - } - return SECSuccess; -} - -/* Tells us if the named suite is exportable - * returns false for unknown suites. - */ -PRBool -SSL_IsExportCipherSuite(PRUint16 cipherSuite) -{ - unsigned int i; - for (i = 0; i < NUM_SUITEINFOS; i++) { - if (suiteInfo[i].cipherSuite == cipherSuite) { - return (PRBool)(suiteInfo[i].isExportable); - } - } - return PR_FALSE; -} - -SECItem * -SSL_GetNegotiatedHostInfo(PRFileDesc *fd) -{ - SECItem *sniName = NULL; - sslSocket *ss; - char *name = NULL; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNegotiatedHostInfo", - SSL_GETPID(), fd)); - return NULL; - } - - if (ss->sec.isServer) { - if (ss->version > SSL_LIBRARY_VERSION_3_0 && - ss->ssl3.initialized) { /* TLS */ - SECItem *crsName; - ssl_GetSpecReadLock(ss); /*********************************/ - crsName = &ss->ssl3.cwSpec->srvVirtName; - if (crsName->data) { - sniName = SECITEM_DupItem(crsName); - } - ssl_ReleaseSpecReadLock(ss); /*----------------------------*/ - } - return sniName; - } - name = SSL_RevealURL(fd); - if (name) { - sniName = PORT_ZNew(SECItem); - if (!sniName) { - PORT_Free(name); - return NULL; - } - sniName->data = (void *)name; - sniName->len = PORT_Strlen(name); - } - return sniName; -} - -SECStatus -SSL_ExportKeyingMaterial(PRFileDesc *fd, - const char *label, unsigned int labelLen, - PRBool hasContext, - const unsigned char *context, unsigned int contextLen, - unsigned char *out, unsigned int outLen) -{ - sslSocket *ss; - unsigned char *val = NULL; - unsigned int valLen, i; - SECStatus rv = SECFailure; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in ExportKeyingMaterial", - SSL_GETPID(), fd)); - return SECFailure; - } - - ssl_GetRecvBufLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (ss->version < SSL_LIBRARY_VERSION_3_1_TLS) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION); - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_ReleaseRecvBufLock(ss); - return SECFailure; - } - - /* construct PRF arguments */ - valLen = SSL3_RANDOM_LENGTH * 2; - if (hasContext) { - valLen += 2 /* PRUint16 length */ + contextLen; - } - val = PORT_Alloc(valLen); - if (!val) { - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_ReleaseRecvBufLock(ss); - return SECFailure; - } - i = 0; - PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); - i += SSL3_RANDOM_LENGTH; - PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH); - i += SSL3_RANDOM_LENGTH; - if (hasContext) { - val[i++] = contextLen >> 8; - val[i++] = contextLen; - PORT_Memcpy(val + i, context, contextLen); - i += contextLen; - } - PORT_Assert(i == valLen); - - /* Allow TLS keying material to be exported sooner, when the master - * secret is available and we have sent ChangeCipherSpec. - */ - ssl_GetSpecReadLock(ss); - if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) { - PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); - rv = SECFailure; - } else { - rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.cwSpec, label, labelLen, val, - valLen, out, outLen); - } - ssl_ReleaseSpecReadLock(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_ReleaseRecvBufLock(ss); - - PORT_ZFree(val, valLen); - return rv; -}
diff --git a/net/third_party/nss/ssl/sslinit.c b/net/third_party/nss/ssl/sslinit.c deleted file mode 100644 index 0f38c0b5..0000000 --- a/net/third_party/nss/ssl/sslinit.c +++ /dev/null
@@ -1,59 +0,0 @@ -/* - * NSS utility functions - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prtypes.h" -#include "prinit.h" -#include "seccomon.h" -#include "secerr.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" - -static int ssl_isInited = 0; -static PRCallOnceType ssl_init = { 0 }; - -PRStatus -ssl_InitCallOnce(void *arg) -{ - int *error = (int *)arg; - SECStatus rv; - - rv = ssl_InitializePRErrorTable(); - if (rv != SECSuccess) { - *error = SEC_ERROR_NO_MEMORY; - return PR_FAILURE; - } -#ifdef DEBUG - ssl3_CheckCipherSuiteOrderConsistency(); -#endif - - rv = ssl3_ApplyNSSPolicy(); - if (rv != SECSuccess) { - *error = PORT_GetError(); - return PR_FAILURE; - } - return PR_SUCCESS; -} - -SECStatus -ssl_Init(void) -{ - PRStatus nrv; - - /* short circuit test if we are already inited */ - if (!ssl_isInited) { - int error; - /* only do this once at init time, block all others until we are done */ - nrv = PR_CallOnceWithArg(&ssl_init, ssl_InitCallOnce, &error); - if (nrv != PR_SUCCESS) { - PORT_SetError(error); - return SECFailure; - } - ssl_isInited = 1; - } - return SECSuccess; -}
diff --git a/net/third_party/nss/ssl/sslmutex.c b/net/third_party/nss/ssl/sslmutex.c deleted file mode 100644 index 0e2edc9..0000000 --- a/net/third_party/nss/ssl/sslmutex.c +++ /dev/null
@@ -1,647 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "seccomon.h" -/* This ifdef should match the one in sslsnce.c */ -#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2) || defined(XP_BEOS) - -#include "sslmutex.h" -#include "prerr.h" - -static SECStatus -single_process_sslMutex_Init(sslMutex* pMutex) -{ - PR_ASSERT(pMutex != 0 && pMutex->u.sslLock == 0); - - pMutex->u.sslLock = PR_NewLock(); - if (!pMutex->u.sslLock) { - return SECFailure; - } - return SECSuccess; -} - -static SECStatus -single_process_sslMutex_Destroy(sslMutex* pMutex) -{ - PR_ASSERT(pMutex != 0); - PR_ASSERT(pMutex->u.sslLock != 0); - if (!pMutex->u.sslLock) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - PR_DestroyLock(pMutex->u.sslLock); - return SECSuccess; -} - -static SECStatus -single_process_sslMutex_Unlock(sslMutex* pMutex) -{ - PR_ASSERT(pMutex != 0); - PR_ASSERT(pMutex->u.sslLock != 0); - if (!pMutex->u.sslLock) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - PR_Unlock(pMutex->u.sslLock); - return SECSuccess; -} - -static SECStatus -single_process_sslMutex_Lock(sslMutex* pMutex) -{ - PR_ASSERT(pMutex != 0); - PR_ASSERT(pMutex->u.sslLock != 0); - if (!pMutex->u.sslLock) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - PR_Lock(pMutex->u.sslLock); - return SECSuccess; -} - -#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) - -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include "unix_err.h" -#include "pratom.h" - -#define SSL_MUTEX_MAGIC 0xfeedfd -#define NONBLOCKING_POSTS 1 /* maybe this is faster */ - -#if NONBLOCKING_POSTS - -#ifndef FNONBLOCK -#define FNONBLOCK O_NONBLOCK -#endif - -static int -setNonBlocking(int fd, int nonBlocking) -{ - int flags; - int err; - - flags = fcntl(fd, F_GETFL, 0); - if (0 > flags) - return flags; - if (nonBlocking) - flags |= FNONBLOCK; - else - flags &= ~FNONBLOCK; - err = fcntl(fd, F_SETFL, flags); - return err; -} -#endif - -SECStatus -sslMutex_Init(sslMutex* pMutex, int shared) -{ - int err; - PR_ASSERT(pMutex); - pMutex->isMultiProcess = (PRBool)(shared != 0); - if (!shared) { - return single_process_sslMutex_Init(pMutex); - } - pMutex->u.pipeStr.mPipes[0] = -1; - pMutex->u.pipeStr.mPipes[1] = -1; - pMutex->u.pipeStr.mPipes[2] = -1; - pMutex->u.pipeStr.nWaiters = 0; - - err = pipe(pMutex->u.pipeStr.mPipes); - if (err) { - nss_MD_unix_map_default_error(errno); - return err; - } -#if NONBLOCKING_POSTS - err = setNonBlocking(pMutex->u.pipeStr.mPipes[1], 1); - if (err) - goto loser; -#endif - - pMutex->u.pipeStr.mPipes[2] = SSL_MUTEX_MAGIC; - -#if defined(LINUX) && defined(i386) - /* Pipe starts out empty */ - return SECSuccess; -#else - /* Pipe starts with one byte. */ - return sslMutex_Unlock(pMutex); -#endif - -loser: - nss_MD_unix_map_default_error(errno); - close(pMutex->u.pipeStr.mPipes[0]); - close(pMutex->u.pipeStr.mPipes[1]); - return SECFailure; -} - -SECStatus -sslMutex_Destroy(sslMutex* pMutex, PRBool processLocal) -{ - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Destroy(pMutex); - } - if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - close(pMutex->u.pipeStr.mPipes[0]); - close(pMutex->u.pipeStr.mPipes[1]); - - if (processLocal) { - return SECSuccess; - } - - pMutex->u.pipeStr.mPipes[0] = -1; - pMutex->u.pipeStr.mPipes[1] = -1; - pMutex->u.pipeStr.mPipes[2] = -1; - pMutex->u.pipeStr.nWaiters = 0; - - return SECSuccess; -} - -#if defined(LINUX) && defined(i386) -/* No memory barrier needed for this platform */ - -/* nWaiters includes the holder of the lock (if any) and the number -** threads waiting for it. After incrementing nWaiters, if the count -** is exactly 1, then you have the lock and may proceed. If the -** count is greater than 1, then you must wait on the pipe. -*/ - -SECStatus -sslMutex_Unlock(sslMutex* pMutex) -{ - PRInt32 newValue; - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Unlock(pMutex); - } - - if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - /* Do Memory Barrier here. */ - newValue = PR_ATOMIC_DECREMENT(&pMutex->u.pipeStr.nWaiters); - if (newValue > 0) { - int cc; - char c = 1; - do { - cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1); - } while (cc < 0 && (errno == EINTR || errno == EAGAIN)); - if (cc != 1) { - if (cc < 0) - nss_MD_unix_map_default_error(errno); - else - PORT_SetError(PR_UNKNOWN_ERROR); - return SECFailure; - } - } - return SECSuccess; -} - -SECStatus -sslMutex_Lock(sslMutex* pMutex) -{ - PRInt32 newValue; - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Lock(pMutex); - } - - if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - newValue = PR_ATOMIC_INCREMENT(&pMutex->u.pipeStr.nWaiters); - /* Do Memory Barrier here. */ - if (newValue > 1) { - int cc; - char c; - do { - cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1); - } while (cc < 0 && errno == EINTR); - if (cc != 1) { - if (cc < 0) - nss_MD_unix_map_default_error(errno); - else - PORT_SetError(PR_UNKNOWN_ERROR); - return SECFailure; - } - } - return SECSuccess; -} - -#else - -/* Using Atomic operations requires the use of a memory barrier instruction -** on PowerPC, Sparc, and Alpha. NSPR's PR_Atomic functions do not perform -** them, and NSPR does not provide a function that does them (e.g. PR_Barrier). -** So, we don't use them on those platforms. -*/ - -SECStatus -sslMutex_Unlock(sslMutex* pMutex) -{ - int cc; - char c = 1; - - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Unlock(pMutex); - } - - if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - do { - cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1); - } while (cc < 0 && (errno == EINTR || errno == EAGAIN)); - if (cc != 1) { - if (cc < 0) - nss_MD_unix_map_default_error(errno); - else - PORT_SetError(PR_UNKNOWN_ERROR); - return SECFailure; - } - - return SECSuccess; -} - -SECStatus -sslMutex_Lock(sslMutex* pMutex) -{ - int cc; - char c; - - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Lock(pMutex); - } - - if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - - do { - cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1); - } while (cc < 0 && errno == EINTR); - if (cc != 1) { - if (cc < 0) - nss_MD_unix_map_default_error(errno); - else - PORT_SetError(PR_UNKNOWN_ERROR); - return SECFailure; - } - - return SECSuccess; -} - -#endif - -#elif defined(WIN32) - -#include "win32err.h" - -/* on Windows, we need to find the optimal type of locking mechanism to use - for the sslMutex. - - There are 3 cases : - 1) single-process, use a PRLock, as for all other platforms - 2) Win95 multi-process, use a Win32 mutex - 3) on WINNT multi-process, use a PRLock + a Win32 mutex - -*/ - -#ifdef WINNT - -SECStatus -sslMutex_2LevelInit(sslMutex *sem) -{ - /* the following adds a PRLock to sslMutex . This is done in each - process of a multi-process server and is only needed on WINNT, if - using fibers. We can't tell if native threads or fibers are used, so - we always do it on WINNT - */ - PR_ASSERT(sem); - if (sem) { - /* we need to reset the sslLock in the children or the single_process init - function below will assert */ - sem->u.sslLock = NULL; - } - return single_process_sslMutex_Init(sem); -} - -static SECStatus -sslMutex_2LevelDestroy(sslMutex *sem) -{ - return single_process_sslMutex_Destroy(sem); -} - -#endif - -SECStatus -sslMutex_Init(sslMutex *pMutex, int shared) -{ -#ifdef WINNT - SECStatus retvalue; -#endif - HANDLE hMutex; - SECURITY_ATTRIBUTES attributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - - PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 || - pMutex->u.sslMutx == - INVALID_HANDLE_VALUE)); - - pMutex->isMultiProcess = (PRBool)(shared != 0); - - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Init(pMutex); - } - -#ifdef WINNT - /* we need a lock on WINNT for fibers in the parent process */ - retvalue = sslMutex_2LevelInit(pMutex); - if (SECSuccess != retvalue) - return SECFailure; -#endif - - if (!pMutex || ((hMutex = pMutex->u.sslMutx) != 0 && - hMutex != - INVALID_HANDLE_VALUE)) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - attributes.bInheritHandle = (shared ? TRUE : FALSE); - hMutex = CreateMutex(&attributes, FALSE, NULL); - if (hMutex == NULL) { - hMutex = INVALID_HANDLE_VALUE; - nss_MD_win32_map_default_error(GetLastError()); - return SECFailure; - } - pMutex->u.sslMutx = hMutex; - return SECSuccess; -} - -SECStatus -sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal) -{ - HANDLE hMutex; - int rv; - int retvalue = SECSuccess; - - PR_ASSERT(pMutex != 0); - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Destroy(pMutex); - } - -/* multi-process mode */ -#ifdef WINNT - /* on NT, get rid of the PRLock used for fibers within a process */ - retvalue = sslMutex_2LevelDestroy(pMutex); -#endif - - PR_ASSERT(pMutex->u.sslMutx != 0 && - pMutex->u.sslMutx != INVALID_HANDLE_VALUE); - if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 || - hMutex == INVALID_HANDLE_VALUE) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - - rv = CloseHandle(hMutex); /* ignore error */ - if (!processLocal && rv) { - pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE; - } - if (!rv) { - nss_MD_win32_map_default_error(GetLastError()); - retvalue = SECFailure; - } - return retvalue; -} - -int -sslMutex_Unlock(sslMutex *pMutex) -{ - BOOL success = FALSE; - HANDLE hMutex; - - PR_ASSERT(pMutex != 0); - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Unlock(pMutex); - } - - PR_ASSERT(pMutex->u.sslMutx != 0 && - pMutex->u.sslMutx != INVALID_HANDLE_VALUE); - if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 || - hMutex == INVALID_HANDLE_VALUE) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - success = ReleaseMutex(hMutex); - if (!success) { - nss_MD_win32_map_default_error(GetLastError()); - return SECFailure; - } -#ifdef WINNT - return single_process_sslMutex_Unlock(pMutex); - /* release PRLock for other fibers in the process */ -#else - return SECSuccess; -#endif -} - -int -sslMutex_Lock(sslMutex *pMutex) -{ - HANDLE hMutex; - DWORD event; - DWORD lastError; - SECStatus rv; - SECStatus retvalue = SECSuccess; - PR_ASSERT(pMutex != 0); - - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Lock(pMutex); - } -#ifdef WINNT - /* lock first to preserve from other threads/fibers - in the same process */ - retvalue = single_process_sslMutex_Lock(pMutex); -#endif - PR_ASSERT(pMutex->u.sslMutx != 0 && - pMutex->u.sslMutx != INVALID_HANDLE_VALUE); - if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 || - hMutex == INVALID_HANDLE_VALUE) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; /* what else ? */ - } - /* acquire the mutex to be the only owner accross all other processes */ - event = WaitForSingleObject(hMutex, INFINITE); - switch (event) { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: - rv = SECSuccess; - break; - - case WAIT_TIMEOUT: -#if defined(WAIT_IO_COMPLETION) - case WAIT_IO_COMPLETION: -#endif - default: /* should never happen. nothing we can do. */ - PR_ASSERT(!("WaitForSingleObject returned invalid value.")); - PORT_SetError(PR_UNKNOWN_ERROR); - rv = SECFailure; - break; - - case WAIT_FAILED: /* failure returns this */ - rv = SECFailure; - lastError = GetLastError(); /* for debugging */ - nss_MD_win32_map_default_error(lastError); - break; - } - - if (!(SECSuccess == retvalue && SECSuccess == rv)) { - return SECFailure; - } - - return SECSuccess; -} - -#elif defined(XP_UNIX) && !defined(DARWIN) - -#include <errno.h> -#include "unix_err.h" - -SECStatus -sslMutex_Init(sslMutex* pMutex, int shared) -{ - int rv; - PR_ASSERT(pMutex); - pMutex->isMultiProcess = (PRBool)(shared != 0); - if (!shared) { - return single_process_sslMutex_Init(pMutex); - } - do { - rv = sem_init(&pMutex->u.sem, shared, 1); - } while (rv < 0 && errno == EINTR); - if (rv < 0) { - nss_MD_unix_map_default_error(errno); - return SECFailure; - } - return SECSuccess; -} - -SECStatus -sslMutex_Destroy(sslMutex* pMutex, PRBool processLocal) -{ - int rv; - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Destroy(pMutex); - } - - /* semaphores are global resources. See SEM_DESTROY(3) man page */ - if (processLocal) { - return SECSuccess; - } - do { - rv = sem_destroy(&pMutex->u.sem); - } while (rv < 0 && errno == EINTR); - if (rv < 0) { - nss_MD_unix_map_default_error(errno); - return SECFailure; - } - return SECSuccess; -} - -SECStatus -sslMutex_Unlock(sslMutex* pMutex) -{ - int rv; - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Unlock(pMutex); - } - do { - rv = sem_post(&pMutex->u.sem); - } while (rv < 0 && errno == EINTR); - if (rv < 0) { - nss_MD_unix_map_default_error(errno); - return SECFailure; - } - return SECSuccess; -} - -SECStatus -sslMutex_Lock(sslMutex* pMutex) -{ - int rv; - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Lock(pMutex); - } - do { - rv = sem_wait(&pMutex->u.sem); - } while (rv < 0 && errno == EINTR); - if (rv < 0) { - nss_MD_unix_map_default_error(errno); - return SECFailure; - } - return SECSuccess; -} - -#else - -SECStatus -sslMutex_Init(sslMutex* pMutex, int shared) -{ - PR_ASSERT(pMutex); - pMutex->isMultiProcess = (PRBool)(shared != 0); - if (!shared) { - return single_process_sslMutex_Init(pMutex); - } - PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !")); - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return SECFailure; -} - -SECStatus -sslMutex_Destroy(sslMutex* pMutex, PRBool processLocal) -{ - PR_ASSERT(pMutex); - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Destroy(pMutex); - } - PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !")); - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return SECFailure; -} - -SECStatus -sslMutex_Unlock(sslMutex* pMutex) -{ - PR_ASSERT(pMutex); - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Unlock(pMutex); - } - PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !")); - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return SECFailure; -} - -SECStatus -sslMutex_Lock(sslMutex* pMutex) -{ - PR_ASSERT(pMutex); - if (PR_FALSE == pMutex->isMultiProcess) { - return single_process_sslMutex_Lock(pMutex); - } - PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !")); - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return SECFailure; -} - -#endif - -#endif
diff --git a/net/third_party/nss/ssl/sslmutex.h b/net/third_party/nss/ssl/sslmutex.h deleted file mode 100644 index 7611148..0000000 --- a/net/third_party/nss/ssl/sslmutex.h +++ /dev/null
@@ -1,128 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef __SSLMUTEX_H_ -#define __SSLMUTEX_H_ 1 - -/* What SSL really wants is portable process-shared unnamed mutexes in - * shared memory, that have the property that if the process that holds - * them dies, they are released automatically, and that (unlike fcntl - * record locking) lock to the thread, not to the process. - * NSPR doesn't provide that. - * Windows has mutexes that meet that description, but they're not portable. - * POSIX mutexes are not automatically released when the holder dies, - * and other processes/threads cannot release the mutex on behalf of the - * dead holder. - * POSIX semaphores can be used to accomplish this on systems that implement - * process-shared unnamed POSIX semaphores, because a watchdog thread can - * discover and release semaphores that were held by a dead process. - * On systems that do not support process-shared POSIX unnamed semaphores, - * they can be emulated using pipes. - * The performance cost of doing that is not yet measured. - * - * So, this API looks a lot like POSIX pthread mutexes. - */ - -#include "prtypes.h" -#include "prlock.h" - -#if defined(NETBSD) -#include <sys/param.h> /* for __NetBSD_Version__ */ -#endif - -#if defined(WIN32) - -#include <wtypes.h> - -typedef struct { - PRBool isMultiProcess; -#ifdef WINNT - /* on WINNT we need both the PRLock and the Win32 mutex for fibers */ - struct { -#else - union { -#endif - PRLock *sslLock; - HANDLE sslMutx; - } u; -} sslMutex; - -typedef int sslPID; - -#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) - -#include <sys/types.h> -#include "prtypes.h" - -typedef struct { - PRBool isMultiProcess; - union { - PRLock *sslLock; - struct { - int mPipes[3]; - PRInt32 nWaiters; - } pipeStr; - } u; -} sslMutex; -typedef pid_t sslPID; - -/* other types of unix, except OS X */ -#elif defined(XP_UNIX) && !defined(DARWIN) - -#include <sys/types.h> /* for pid_t */ -#include <semaphore.h> /* for sem_t, and sem_* functions */ - -typedef struct { - PRBool isMultiProcess; - union { - PRLock *sslLock; - sem_t sem; - } u; -} sslMutex; - -typedef pid_t sslPID; - -#else /* no support for cross-process locking */ - -/* what platform is this ?? */ - -typedef struct { - PRBool isMultiProcess; - union { - PRLock *sslLock; - /* include cross-process locking mechanism here */ - } u; -} sslMutex; - -#ifdef DARWIN -typedef pid_t sslPID; -#else -typedef int sslPID; -#endif - -#endif - -#include "seccomon.h" - -SEC_BEGIN_PROTOS - -extern SECStatus sslMutex_Init(sslMutex *sem, int shared); - -/* If processLocal is set to true, then just free resources which are *only* associated - * with the current process. Leave any shared resources (including the state of - * shared memory) intact. */ -extern SECStatus sslMutex_Destroy(sslMutex *sem, PRBool processLocal); - -extern SECStatus sslMutex_Unlock(sslMutex *sem); - -extern SECStatus sslMutex_Lock(sslMutex *sem); - -#ifdef WINNT - -extern SECStatus sslMutex_2LevelInit(sslMutex *sem); - -#endif - -SEC_END_PROTOS - -#endif
diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c deleted file mode 100644 index 99591cc1..0000000 --- a/net/third_party/nss/ssl/sslnonce.c +++ /dev/null
@@ -1,467 +0,0 @@ -/* - * This file implements the CLIENT Session ID cache. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "cert.h" -#include "pk11pub.h" -#include "secitem.h" -#include "ssl.h" -#include "nss.h" - -#include "sslimpl.h" -#include "sslproto.h" -#include "nssilock.h" -#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS) -#include <time.h> -#endif - -PRUint32 ssl_sid_timeout = 100; -PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */ - -static sslSessionID *cache = NULL; -static PZLock *cacheLock = NULL; - -/* sids can be in one of 4 states: - * - * never_cached, created, but not yet put into cache. - * in_client_cache, in the client cache's linked list. - * in_server_cache, entry came from the server's cache file. - * invalid_cache has been removed from the cache. - */ - -#define LOCK_CACHE lock_cache() -#define UNLOCK_CACHE PZ_Unlock(cacheLock) - -static PRCallOnceType lockOnce; - -/* FreeSessionCacheLocks is a callback from NSS_RegisterShutdown which destroys - * the session cache locks on shutdown and resets them to their initial - * state. */ -static SECStatus -FreeSessionCacheLocks(void *appData, void *nssData) -{ - static const PRCallOnceType pristineCallOnce; - SECStatus rv; - - if (!cacheLock) { - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return SECFailure; - } - - PZ_DestroyLock(cacheLock); - cacheLock = NULL; - - rv = ssl_FreeSymWrapKeysLock(); - if (rv != SECSuccess) { - return rv; - } - - lockOnce = pristineCallOnce; - return SECSuccess; -} - -/* InitSessionCacheLocks is called, protected by lockOnce, to create the - * session cache locks. */ -static PRStatus -InitSessionCacheLocks(void) -{ - SECStatus rv; - - cacheLock = PZ_NewLock(nssILockCache); - if (cacheLock == NULL) { - return PR_FAILURE; - } - rv = ssl_InitSymWrapKeysLock(); - if (rv != SECSuccess) { - PRErrorCode error = PORT_GetError(); - PZ_DestroyLock(cacheLock); - cacheLock = NULL; - PORT_SetError(error); - return PR_FAILURE; - } - - rv = NSS_RegisterShutdown(FreeSessionCacheLocks, NULL); - PORT_Assert(SECSuccess == rv); - if (SECSuccess != rv) { - return PR_FAILURE; - } - return PR_SUCCESS; -} - -SECStatus -ssl_InitSessionCacheLocks() -{ - return (PR_SUCCESS == - PR_CallOnce(&lockOnce, InitSessionCacheLocks)) - ? SECSuccess - : SECFailure; -} - -static void -lock_cache(void) -{ - ssl_InitSessionCacheLocks(); - PZ_Lock(cacheLock); -} - -/* BEWARE: This function gets called for both client and server SIDs !! - * If the unreferenced sid is not in the cache, Free sid and its contents. - */ -static void -ssl_DestroySID(sslSessionID *sid) -{ - int i; - SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached)); - PORT_Assert(sid->references == 0); - PORT_Assert(sid->cached != in_client_cache); - - if (sid->version < SSL_LIBRARY_VERSION_3_0) { - SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE); - SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE); - } else { - if (sid->u.ssl3.locked.sessionTicket.ticket.data) { - SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket, - PR_FALSE); - } - if (sid->u.ssl3.srvName.data) { - SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); - } - if (sid->u.ssl3.signedCertTimestamps.data) { - SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE); - } - if (sid->u.ssl3.originalHandshakeHash.data) { - SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); - } - - if (sid->u.ssl3.lock) { - PR_DestroyRWLock(sid->u.ssl3.lock); - } - } - - if (sid->peerID != NULL) - PORT_Free((void *)sid->peerID); /* CONST */ - - if (sid->urlSvrName != NULL) - PORT_Free((void *)sid->urlSvrName); /* CONST */ - - if (sid->peerCert) { - CERT_DestroyCertificate(sid->peerCert); - } - for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { - CERT_DestroyCertificate(sid->peerCertChain[i]); - } - if (sid->peerCertStatus.items) { - SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE); - } - - if (sid->localCert) { - CERT_DestroyCertificate(sid->localCert); - } - - PORT_ZFree(sid, sizeof(sslSessionID)); -} - -/* BEWARE: This function gets called for both client and server SIDs !! - * Decrement reference count, and - * free sid if ref count is zero, and sid is not in the cache. - * Does NOT remove from the cache first. - * If the sid is still in the cache, it is left there until next time - * the cache list is traversed. - */ -static void -ssl_FreeLockedSID(sslSessionID *sid) -{ - PORT_Assert(sid->references >= 1); - if (--sid->references == 0) { - ssl_DestroySID(sid); - } -} - -/* BEWARE: This function gets called for both client and server SIDs !! - * Decrement reference count, and - * free sid if ref count is zero, and sid is not in the cache. - * Does NOT remove from the cache first. - * These locks are necessary because the sid _might_ be in the cache list. - */ -void -ssl_FreeSID(sslSessionID *sid) -{ - LOCK_CACHE; - ssl_FreeLockedSID(sid); - UNLOCK_CACHE; -} - -/************************************************************************/ - -/* -** Lookup sid entry in cache by Address, port, and peerID string. -** If found, Increment reference count, and return pointer to caller. -** If it has timed out or ref count is zero, remove from list and free it. -*/ - -sslSessionID * -ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, - const char *urlSvrName) -{ - sslSessionID **sidp; - sslSessionID *sid; - PRUint32 now; - - if (!urlSvrName) - return NULL; - now = ssl_Time(); - LOCK_CACHE; - sidp = &cache; - while ((sid = *sidp) != 0) { - PORT_Assert(sid->cached == in_client_cache); - PORT_Assert(sid->references >= 1); - - SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid)); - - if (sid->expirationTime < now) { - /* - ** This session-id timed out. - ** Don't even care who it belongs to, blow it out of our cache. - */ - SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d", - now - sid->creationTime, sid->references)); - - *sidp = sid->next; /* delink it from the list. */ - sid->cached = invalid_cache; /* mark not on list. */ - ssl_FreeLockedSID(sid); /* drop ref count, free. */ - } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */ - (sid->port == port) && /* server port matches */ - /* proxy (peerID) matches */ - (((peerID == NULL) && (sid->peerID == NULL)) || - ((peerID != NULL) && (sid->peerID != NULL) && - PORT_Strcmp(sid->peerID, peerID) == 0)) && - /* is cacheable */ - (sid->version < SSL_LIBRARY_VERSION_3_0 || - sid->u.ssl3.keys.resumable) && - /* server hostname matches. */ - (sid->urlSvrName != NULL) && - (0 == PORT_Strcmp(urlSvrName, sid->urlSvrName))) { - /* Hit */ - sid->lastAccessTime = now; - sid->references++; - break; - } else { - sidp = &sid->next; - } - } - UNLOCK_CACHE; - return sid; -} - -/* -** Add an sid to the cache or return a previously cached entry to the cache. -** Although this is static, it is called via ss->sec.cache(). -*/ -static void -CacheSID(sslSessionID *sid) -{ - PRUint32 expirationPeriod; - - PORT_Assert(sid->cached == never_cached); - - SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x " - "time=%x cached=%d", - sid, sid->cached, sid->addr.pr_s6_addr32[0], - sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2], - sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime, - sid->cached)); - - if (!sid->urlSvrName) { - /* don't cache this SID because it can never be matched */ - return; - } - - /* XXX should be different trace for version 2 vs. version 3 */ - if (sid->version < SSL_LIBRARY_VERSION_3_0) { - expirationPeriod = ssl_sid_timeout; - PRINT_BUF(8, (0, "sessionID:", - sid->u.ssl2.sessionID, sizeof(sid->u.ssl2.sessionID))); - PRINT_BUF(8, (0, "masterKey:", - sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len)); - PRINT_BUF(8, (0, "cipherArg:", - sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len)); - } else { - if (sid->u.ssl3.sessionIDLength == 0 && - sid->u.ssl3.locked.sessionTicket.ticket.data == NULL) - return; - - /* Client generates the SessionID if this was a stateless resume. */ - if (sid->u.ssl3.sessionIDLength == 0) { - SECStatus rv; - rv = PK11_GenerateRandom(sid->u.ssl3.sessionID, - SSL3_SESSIONID_BYTES); - if (rv != SECSuccess) - return; - sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES; - } - expirationPeriod = ssl3_sid_timeout; - PRINT_BUF(8, (0, "sessionID:", - sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength)); - - sid->u.ssl3.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL); - if (!sid->u.ssl3.lock) { - return; - } - } - PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0); - if (!sid->creationTime) - sid->lastAccessTime = sid->creationTime = ssl_Time(); - if (!sid->expirationTime) - sid->expirationTime = sid->creationTime + expirationPeriod; - - /* - * Put sid into the cache. Bump reference count to indicate that - * cache is holding a reference. Uncache will reduce the cache - * reference. - */ - LOCK_CACHE; - sid->references++; - sid->cached = in_client_cache; - sid->next = cache; - cache = sid; - UNLOCK_CACHE; -} - -/* - * If sid "zap" is in the cache, - * removes sid from cache, and decrements reference count. - * Caller must hold cache lock. - */ -static void -UncacheSID(sslSessionID *zap) -{ - sslSessionID **sidp = &cache; - sslSessionID *sid; - - if (zap->cached != in_client_cache) { - return; - } - - SSL_TRC(8, ("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x " - "time=%x cipher=%d", - zap, zap->cached, zap->addr.pr_s6_addr32[0], - zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2], - zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime, - zap->u.ssl2.cipherType)); - if (zap->version < SSL_LIBRARY_VERSION_3_0) { - PRINT_BUF(8, (0, "sessionID:", - zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID))); - PRINT_BUF(8, (0, "masterKey:", - zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len)); - PRINT_BUF(8, (0, "cipherArg:", - zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len)); - } - - /* See if it's in the cache, if so nuke it */ - while ((sid = *sidp) != 0) { - if (sid == zap) { - /* - ** Bingo. Reduce reference count by one so that when - ** everyone is done with the sid we can free it up. - */ - *sidp = zap->next; - zap->cached = invalid_cache; - ssl_FreeLockedSID(zap); - return; - } - sidp = &sid->next; - } -} - -/* If sid "zap" is in the cache, - * removes sid from cache, and decrements reference count. - * Although this function is static, it is called externally via - * ss->sec.uncache(). - */ -static void -LockAndUncacheSID(sslSessionID *zap) -{ - LOCK_CACHE; - UncacheSID(zap); - UNLOCK_CACHE; -} - -/* choose client or server cache functions for this sslsocket. */ -void -ssl_ChooseSessionIDProcs(sslSecurityInfo *sec) -{ - if (sec->isServer) { - sec->cache = ssl_sid_cache; - sec->uncache = ssl_sid_uncache; - } else { - sec->cache = CacheSID; - sec->uncache = LockAndUncacheSID; - } -} - -/* wipe out the entire client session cache. */ -void -SSL_ClearSessionCache(void) -{ - LOCK_CACHE; - while (cache != NULL) - UncacheSID(cache); - UNLOCK_CACHE; -} - -/* returns an unsigned int containing the number of seconds in PR_Now() */ -PRUint32 -ssl_Time(void) -{ - PRUint32 myTime; -#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS) - myTime = time(NULL); /* accurate until the year 2038. */ -#else - /* portable, but possibly slower */ - PRTime now; - PRInt64 ll; - - now = PR_Now(); - LL_I2L(ll, 1000000L); - LL_DIV(now, now, ll); - LL_L2UI(myTime, now); -#endif - return myTime; -} - -void -ssl3_SetSIDSessionTicket(sslSessionID *sid, - /*in/out*/ NewSessionTicket *newSessionTicket) -{ - PORT_Assert(sid); - PORT_Assert(newSessionTicket); - PORT_Assert(newSessionTicket->ticket.data); - PORT_Assert(newSessionTicket->ticket.len != 0); - - /* if sid->u.ssl3.lock, we are updating an existing entry that is already - * cached or was once cached, so we need to acquire and release the write - * lock. Otherwise, this is a new session that isn't shared with anything - * yet, so no locking is needed. - */ - if (sid->u.ssl3.lock) { - PR_RWLock_Wlock(sid->u.ssl3.lock); - if (sid->u.ssl3.locked.sessionTicket.ticket.data) { - SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket, - PR_FALSE); - } - } - - PORT_Assert(!sid->u.ssl3.locked.sessionTicket.ticket.data); - - /* Do a shallow copy, moving the ticket data. */ - sid->u.ssl3.locked.sessionTicket = *newSessionTicket; - newSessionTicket->ticket.data = NULL; - newSessionTicket->ticket.len = 0; - - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } -}
diff --git a/net/third_party/nss/ssl/sslproto.h b/net/third_party/nss/ssl/sslproto.h deleted file mode 100644 index 4fa260d..0000000 --- a/net/third_party/nss/ssl/sslproto.h +++ /dev/null
@@ -1,286 +0,0 @@ -/* - * Various and sundry protocol constants. DON'T CHANGE THESE. These values - * are mostly defined by the SSL2, SSL3, or TLS protocol specifications. - * Cipher kinds and ciphersuites are part of the public API. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __sslproto_h_ -#define __sslproto_h_ - -/* clang-format off */ - -/* All versions less than 3_0 are treated as SSL version 2 */ -#define SSL_LIBRARY_VERSION_2 0x0002 -#define SSL_LIBRARY_VERSION_3_0 0x0300 -#define SSL_LIBRARY_VERSION_TLS_1_0 0x0301 -#define SSL_LIBRARY_VERSION_TLS_1_1 0x0302 -#define SSL_LIBRARY_VERSION_TLS_1_2 0x0303 -#define SSL_LIBRARY_VERSION_TLS_1_3 0x0304 - -/* Note: this is the internal format, not the wire format */ -#define SSL_LIBRARY_VERSION_DTLS_1_0 0x0302 -#define SSL_LIBRARY_VERSION_DTLS_1_2 0x0303 -#define SSL_LIBRARY_VERSION_DTLS_1_3 0x0304 - -/* deprecated old name */ -#define SSL_LIBRARY_VERSION_3_1_TLS SSL_LIBRARY_VERSION_TLS_1_0 - -/* The DTLS versions used in the spec */ -#define SSL_LIBRARY_VERSION_DTLS_1_0_WIRE ((~0x0100) & 0xffff) -#define SSL_LIBRARY_VERSION_DTLS_1_2_WIRE ((~0x0102) & 0xffff) -#define SSL_LIBRARY_VERSION_DTLS_1_3_WIRE ((~0x0103) & 0xffff) - -/* Header lengths of some of the messages */ -#define SSL_HL_ERROR_HBYTES 3 -#define SSL_HL_CLIENT_HELLO_HBYTES 9 -#define SSL_HL_CLIENT_MASTER_KEY_HBYTES 10 -#define SSL_HL_CLIENT_FINISHED_HBYTES 1 -#define SSL_HL_SERVER_HELLO_HBYTES 11 -#define SSL_HL_SERVER_VERIFY_HBYTES 1 -#define SSL_HL_SERVER_FINISHED_HBYTES 1 -#define SSL_HL_REQUEST_CERTIFICATE_HBYTES 2 -#define SSL_HL_CLIENT_CERTIFICATE_HBYTES 6 - -/* Security handshake protocol codes */ -#define SSL_MT_ERROR 0 -#define SSL_MT_CLIENT_HELLO 1 -#define SSL_MT_CLIENT_MASTER_KEY 2 -#define SSL_MT_CLIENT_FINISHED 3 -#define SSL_MT_SERVER_HELLO 4 -#define SSL_MT_SERVER_VERIFY 5 -#define SSL_MT_SERVER_FINISHED 6 -#define SSL_MT_REQUEST_CERTIFICATE 7 -#define SSL_MT_CLIENT_CERTIFICATE 8 - -/* Certificate types */ -#define SSL_CT_X509_CERTIFICATE 0x01 -#if 0 /* XXX Not implemented yet */ -#define SSL_PKCS6_CERTIFICATE 0x02 -#endif -#define SSL_AT_MD5_WITH_RSA_ENCRYPTION 0x01 - -/* Error codes */ -#define SSL_PE_NO_CYPHERS 0x0001 -#define SSL_PE_NO_CERTIFICATE 0x0002 -#define SSL_PE_BAD_CERTIFICATE 0x0004 -#define SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006 - -/* Cypher kinds (not the spec version!) */ -#define SSL_CK_RC4_128_WITH_MD5 0x01 -#define SSL_CK_RC4_128_EXPORT40_WITH_MD5 0x02 -#define SSL_CK_RC2_128_CBC_WITH_MD5 0x03 -#define SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 0x04 -#define SSL_CK_IDEA_128_CBC_WITH_MD5 0x05 -#define SSL_CK_DES_64_CBC_WITH_MD5 0x06 -#define SSL_CK_DES_192_EDE3_CBC_WITH_MD5 0x07 - -/* Cipher enables. These are used only for SSL_EnableCipher - * These values define the SSL2 suites, and do not colide with the - * SSL3 Cipher suites defined below. - */ -#define SSL_EN_RC4_128_WITH_MD5 0xFF01 -#define SSL_EN_RC4_128_EXPORT40_WITH_MD5 0xFF02 -#define SSL_EN_RC2_128_CBC_WITH_MD5 0xFF03 -#define SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5 0xFF04 -#define SSL_EN_IDEA_128_CBC_WITH_MD5 0xFF05 -#define SSL_EN_DES_64_CBC_WITH_MD5 0xFF06 -#define SSL_EN_DES_192_EDE3_CBC_WITH_MD5 0xFF07 - -/* Deprecated SSL 3.0 & libssl names replaced by IANA-registered TLS names. */ -#ifndef SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -#define SSL_NULL_WITH_NULL_NULL TLS_NULL_WITH_NULL_NULL -#define SSL_RSA_WITH_NULL_MD5 TLS_RSA_WITH_NULL_MD5 -#define SSL_RSA_WITH_NULL_SHA TLS_RSA_WITH_NULL_SHA -#define SSL_RSA_EXPORT_WITH_RC4_40_MD5 TLS_RSA_EXPORT_WITH_RC4_40_MD5 -#define SSL_RSA_WITH_RC4_128_MD5 TLS_RSA_WITH_RC4_128_MD5 -#define SSL_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_RC4_128_SHA -#define SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 -#define SSL_RSA_WITH_IDEA_CBC_SHA TLS_RSA_WITH_IDEA_CBC_SHA -#define SSL_RSA_EXPORT_WITH_DES40_CBC_SHA TLS_RSA_EXPORT_WITH_DES40_CBC_SHA -#define SSL_RSA_WITH_DES_CBC_SHA TLS_RSA_WITH_DES_CBC_SHA -#define SSL_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA -#define SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA -#define SSL_DH_DSS_WITH_DES_CBC_SHA TLS_DH_DSS_WITH_DES_CBC_SHA -#define SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA -#define SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA -#define SSL_DH_RSA_WITH_DES_CBC_SHA TLS_DH_RSA_WITH_DES_CBC_SHA -#define SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA -#define SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA -#define SSL_DHE_DSS_WITH_DES_CBC_SHA TLS_DHE_DSS_WITH_DES_CBC_SHA -#define SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA -#define SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA -#define SSL_DHE_RSA_WITH_DES_CBC_SHA TLS_DHE_RSA_WITH_DES_CBC_SHA -#define SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA -#define SSL_DH_ANON_WITH_RC4_128_MD5 TLS_DH_anon_WITH_RC4_128_MD5 -#define SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA -#define SSL_DH_ANON_WITH_DES_CBC_SHA TLS_DH_anon_WITH_DES_CBC_SHA -#define SSL_DH_ANON_WITH_3DES_EDE_CBC_SHA TLS_DH_anon_WITH_3DES_EDE_CBC_SHA -#define SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5 TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 -#define TLS_DH_ANON_WITH_AES_128_CBC_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA -#define TLS_DH_ANON_WITH_AES_256_CBC_SHA TLS_DH_anon_WITH_AES_256_CBC_SHA -#define TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA -#define TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA -#endif - -#define TLS_NULL_WITH_NULL_NULL 0x0000 - -#define TLS_RSA_WITH_NULL_MD5 0x0001 -#define TLS_RSA_WITH_NULL_SHA 0x0002 -#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 -#define TLS_RSA_WITH_RC4_128_MD5 0x0004 -#define TLS_RSA_WITH_RC4_128_SHA 0x0005 -#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 -#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 -#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 -#define TLS_RSA_WITH_DES_CBC_SHA 0x0009 -#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000a - -#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000b -#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000c -#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000d -#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000e -#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000f -#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 - -#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 -#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 -#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 -#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 -#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 -#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 - -#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 -#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 -#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 -#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001a -#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001b - -#define SSL_FORTEZZA_DMS_WITH_NULL_SHA 0x001c /* deprecated */ -#define SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA 0x001d /* deprecated */ -#define SSL_FORTEZZA_DMS_WITH_RC4_128_SHA 0x001e /* deprecated */ - -#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F -#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 -#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 -#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 -#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 -#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 - -#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 -#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 -#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 -#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 -#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 -#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A -#define TLS_RSA_WITH_NULL_SHA256 0x003B -#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C -#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D - -#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040 -#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0041 -#define TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x0042 -#define TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0043 -#define TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x0044 -#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0045 -#define TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA 0x0046 - -#define TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x0062 -#define TLS_RSA_EXPORT1024_WITH_RC4_56_SHA 0x0064 - -#define TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x0063 -#define TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x0065 -#define TLS_DHE_DSS_WITH_RC4_128_SHA 0x0066 -#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 -#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A -#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B - -#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0084 -#define TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x0085 -#define TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0086 -#define TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x0087 -#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0088 -#define TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA 0x0089 - -#define TLS_RSA_WITH_SEED_CBC_SHA 0x0096 - -#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C -#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E -#define TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2 - -/* TLS "Signaling Cipher Suite Value" (SCSV). May be requested by client. - * Must NEVER be chosen by server. SSL 3.0 server acknowledges by sending - * back an empty Renegotiation Info (RI) server hello extension. - */ -#define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF - -/* TLS_FALLBACK_SCSV is a signaling cipher suite value that indicates that a - * handshake is the result of TLS version fallback. - */ -#define TLS_FALLBACK_SCSV 0x5600 - -/* Cipher Suite Values starting with 0xC000 are defined in informational - * RFCs. - */ -#define TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 -#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 -#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 -#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 -#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 - -#define TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 -#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 -#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 -#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 -#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A - -#define TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B -#define TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C -#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D -#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E -#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F - -#define TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 -#define TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 -#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 -#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 -#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 - -#define TLS_ECDH_anon_WITH_NULL_SHA 0xC015 -#define TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016 -#define TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017 -#define TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018 -#define TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019 - -#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 -#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 - -#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B -#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D -#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F -#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 - -#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8 -#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9 -#define TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA - -/* Netscape "experimental" cipher suites. */ -#define SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA 0xffe0 -#define SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA 0xffe1 - -/* New non-experimental openly spec'ed versions of those cipher suites. */ -#define SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA 0xfeff -#define SSL_RSA_FIPS_WITH_DES_CBC_SHA 0xfefe - -/* DTLS-SRTP cipher suites from RFC 5764 */ -/* If you modify this, also modify MAX_DTLS_SRTP_CIPHER_SUITES in sslimpl.h */ -#define SRTP_AES128_CM_HMAC_SHA1_80 0x0001 -#define SRTP_AES128_CM_HMAC_SHA1_32 0x0002 -#define SRTP_NULL_HMAC_SHA1_80 0x0005 -#define SRTP_NULL_HMAC_SHA1_32 0x0006 - -/* clang-format on */ - -#endif /* __sslproto_h_ */
diff --git a/net/third_party/nss/ssl/sslreveal.c b/net/third_party/nss/ssl/sslreveal.c deleted file mode 100644 index 4c124a1d..0000000 --- a/net/third_party/nss/ssl/sslreveal.c +++ /dev/null
@@ -1,110 +0,0 @@ -/* - * Accessor functions for SSLSocket private members. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "cert.h" -#include "ssl.h" -#include "certt.h" -#include "sslimpl.h" - -/* given PRFileDesc, returns a copy of certificate associated with the socket - * the caller should delete the cert when done with SSL_DestroyCertificate - */ -CERTCertificate * -SSL_RevealCert(PRFileDesc *fd) -{ - CERTCertificate *cert = NULL; - sslSocket *sslsocket = NULL; - - sslsocket = ssl_FindSocket(fd); - - /* CERT_DupCertificate increases reference count and returns pointer to - * the same cert - */ - if (sslsocket && sslsocket->sec.peerCert) - cert = CERT_DupCertificate(sslsocket->sec.peerCert); - - return cert; -} - -/* given PRFileDesc, returns a pointer to PinArg associated with the socket - */ -void * -SSL_RevealPinArg(PRFileDesc *fd) -{ - sslSocket *sslsocket = NULL; - void *PinArg = NULL; - - sslsocket = ssl_FindSocket(fd); - - /* is pkcs11PinArg part of the sslSocket or sslSecurityInfo ? */ - if (sslsocket) - PinArg = sslsocket->pkcs11PinArg; - - return PinArg; -} - -/* given PRFileDesc, returns a pointer to the URL associated with the socket - * the caller should free url when done - */ -char * -SSL_RevealURL(PRFileDesc *fd) -{ - sslSocket *sslsocket = NULL; - char *url = NULL; - - sslsocket = ssl_FindSocket(fd); - - if (sslsocket && sslsocket->url) - url = PL_strdup(sslsocket->url); - - return url; -} - -/* given PRFileDesc, returns status information related to extensions - * negotiated with peer during the handshake. - */ - -SECStatus -SSL_HandshakeNegotiatedExtension(PRFileDesc *socket, - SSLExtensionType extId, - PRBool *pYes) -{ - /* some decisions derived from SSL_GetChannelInfo */ - sslSocket *sslsocket = NULL; - - if (!pYes) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - sslsocket = ssl_FindSocket(socket); - if (!sslsocket) { - SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeNegotiatedExtension", - SSL_GETPID(), socket)); - return SECFailure; - } - - *pYes = PR_FALSE; - - /* according to public API SSL_GetChannelInfo, this doesn't need a lock */ - if (sslsocket->opt.useSecurity) { - if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */ - /* now we know this socket went through ssl3_InitState() and - * ss->xtnData got initialized, which is the only member accessed by - * ssl3_ExtensionNegotiated(); - * Member xtnData appears to get accessed in functions that handle - * the handshake (hello messages and extension sending), - * therefore the handshake lock should be sufficient. - */ - ssl_GetSSL3HandshakeLock(sslsocket); - *pYes = ssl3_ExtensionNegotiated(sslsocket, extId); - ssl_ReleaseSSL3HandshakeLock(sslsocket); - } - } - - return SECSuccess; -}
diff --git a/net/third_party/nss/ssl/sslsecur.c b/net/third_party/nss/ssl/sslsecur.c deleted file mode 100644 index 129f1f3..0000000 --- a/net/third_party/nss/ssl/sslsecur.c +++ /dev/null
@@ -1,1739 +0,0 @@ -/* - * Various SSL functions. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "cert.h" -#include "secitem.h" -#include "keyhi.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "secoid.h" /* for SECOID_GetALgorithmTag */ -#include "pk11func.h" /* for PK11_GenerateRandom */ -#include "nss.h" /* for NSS_RegisterShutdown */ -#include "prinit.h" /* for PR_CallOnceWithArg */ - -#define MAX_BLOCK_CYPHER_SIZE 32 - -#define TEST_FOR_FAILURE /* reminder */ -#define SET_ERROR_CODE /* reminder */ - -/* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock. - * - * Currently, the list of functions called through ss->handshake is: - * - * In sslsocks.c: - * SocksGatherRecord - * SocksHandleReply - * SocksStartGather - * - * In sslcon.c: - * ssl_GatherRecord1stHandshake - * ssl2_HandleClientSessionKeyMessage - * ssl2_HandleMessage - * ssl2_HandleVerifyMessage - * ssl2_BeginClientHandshake - * ssl2_BeginServerHandshake - * ssl2_HandleClientHelloMessage - * ssl2_HandleServerHelloMessage - * - * The ss->handshake function returns SECWouldBlock under these conditions: - * 1. ssl_GatherRecord1stHandshake called ssl2_GatherData which read in - * the beginning of an SSL v3 hello message and returned SECWouldBlock - * to switch to SSL v3 handshake processing. - * - * 2. ssl2_HandleClientHelloMessage discovered version 3.0 in the incoming - * v2 client hello msg, and called ssl3_HandleV2ClientHello which - * returned SECWouldBlock. - * - * 3. SECWouldBlock was returned by one of the callback functions, via - * one of these paths: - * - ssl2_HandleMessage() -> ssl2_HandleRequestCertificate() -> - * ss->getClientAuthData() - * - * - ssl2_HandleServerHelloMessage() -> ss->handleBadCert() - * - * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> - * ssl3_HandleRecord() -> ssl3_HandleHandshake() -> - * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() -> - * ss->handleBadCert() - * - * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> - * ssl3_HandleRecord() -> ssl3_HandleHandshake() -> - * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() -> - * ss->getClientAuthData() - * - * Called from: SSL_ForceHandshake (below), - * ssl_SecureRecv (below) and - * ssl_SecureSend (below) - * from: WaitForResponse in sslsocks.c - * ssl_SocksRecv in sslsocks.c - * ssl_SocksSend in sslsocks.c - * - * Caller must hold the (write) handshakeLock. - */ -int -ssl_Do1stHandshake(sslSocket *ss) -{ - int rv = SECSuccess; - int loopCount = 0; - - do { - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->handshake == 0) { - /* Previous handshake finished. Switch to next one */ - ss->handshake = ss->nextHandshake; - ss->nextHandshake = 0; - } - if (ss->handshake == 0) { - /* Previous handshake finished. Switch to security handshake */ - ss->handshake = ss->securityHandshake; - ss->securityHandshake = 0; - } - if (ss->handshake == 0) { - /* for v3 this is done in ssl3_FinishHandshake */ - if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) { - ssl_GetRecvBufLock(ss); - ss->gs.recordLen = 0; - ssl_FinishHandshake(ss); - ssl_ReleaseRecvBufLock(ss); - } - break; - } - rv = (*ss->handshake)(ss); - ++loopCount; - /* This code must continue to loop on SECWouldBlock, - * or any positive value. See XXX_1 comments. - */ - } while (rv != SECFailure); /* was (rv >= 0); XXX_1 */ - - PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss)); - - if (rv == SECWouldBlock) { - PORT_SetError(PR_WOULD_BLOCK_ERROR); - rv = SECFailure; - } - return rv; -} - -void -ssl_FinishHandshake(sslSocket *ss) -{ - PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - - SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); - - ss->firstHsDone = PR_TRUE; - ss->enoughFirstHsDone = PR_TRUE; - ss->gs.writeOffset = 0; - ss->gs.readOffset = 0; - - if (ss->handshakeCallback) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_3_0 || - (ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == - ssl_preinfo_all); - (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); - } -} - -/* - * Handshake function that blocks. Used to force a - * retry on a connection on the next read/write. - */ -static SECStatus -ssl3_AlwaysBlock(sslSocket *ss) -{ - PORT_SetError(PR_WOULD_BLOCK_ERROR); /* perhaps redundant. */ - return SECWouldBlock; -} - -/* - * set the initial handshake state machine to block - */ -void -ssl3_SetAlwaysBlock(sslSocket *ss) -{ - if (!ss->firstHsDone) { - ss->handshake = ssl3_AlwaysBlock; - ss->nextHandshake = 0; - } -} - -static SECStatus -ssl_SetTimeout(PRFileDesc *fd, PRIntervalTime timeout) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SetTimeout", SSL_GETPID(), fd)); - return SECFailure; - } - SSL_LOCK_READER(ss); - ss->rTimeout = timeout; - if (ss->opt.fdx) { - SSL_LOCK_WRITER(ss); - } - ss->wTimeout = timeout; - if (ss->opt.fdx) { - SSL_UNLOCK_WRITER(ss); - } - SSL_UNLOCK_READER(ss); - return SECSuccess; -} - -/* Acquires and releases HandshakeLock. -*/ -SECStatus -SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) -{ - sslSocket *ss; - SECStatus status; - PRNetAddr addr; - - ss = ssl_FindSocket(s); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in ResetHandshake", SSL_GETPID(), s)); - return SECFailure; - } - - /* Don't waste my time */ - if (!ss->opt.useSecurity) - return SECSuccess; - - SSL_LOCK_READER(ss); - SSL_LOCK_WRITER(ss); - - /* Reset handshake state */ - ssl_Get1stHandshakeLock(ss); - - ss->firstHsDone = PR_FALSE; - ss->enoughFirstHsDone = PR_FALSE; - if (asServer) { - ss->handshake = ssl2_BeginServerHandshake; - ss->handshaking = sslHandshakingAsServer; - } else { - ss->handshake = ssl2_BeginClientHandshake; - ss->handshaking = sslHandshakingAsClient; - } - ss->nextHandshake = 0; - ss->securityHandshake = 0; - - ssl_GetRecvBufLock(ss); - status = ssl_InitGather(&ss->gs); - ssl_ReleaseRecvBufLock(ss); - - ssl_GetSSL3HandshakeLock(ss); - ss->ssl3.hs.canFalseStart = PR_FALSE; - ss->ssl3.hs.restartTarget = NULL; - - /* - ** Blow away old security state and get a fresh setup. - */ - ssl_GetXmitBufLock(ss); - ssl_ResetSecurityInfo(&ss->sec, PR_TRUE); - status = ssl_CreateSecurityInfo(ss); - ssl_ReleaseXmitBufLock(ss); - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - if (!ss->TCPconnected) - ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); - - SSL_UNLOCK_WRITER(ss); - SSL_UNLOCK_READER(ss); - - return status; -} - -/* For SSLv2, does nothing but return an error. -** For SSLv3, flushes SID cache entry (if requested), -** and then starts new client hello or hello request. -** Acquires and releases HandshakeLock. -*/ -SECStatus -SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) -{ - sslSocket *ss; - SECStatus rv; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd)); - return SECFailure; - } - - if (!ss->opt.useSecurity) - return SECSuccess; - - ssl_Get1stHandshakeLock(ss); - - /* SSL v2 protocol does not support subsequent handshakes. */ - if (ss->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - rv = SECFailure; - } else { - ssl_GetSSL3HandshakeLock(ss); - rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */ - ssl_ReleaseSSL3HandshakeLock(ss); - } - - ssl_Release1stHandshakeLock(ss); - - return rv; -} - -/* -** Same as above, but with an I/O timeout. - */ -SSL_IMPORT SECStatus -SSL_ReHandshakeWithTimeout(PRFileDesc *fd, - PRBool flushCache, - PRIntervalTime timeout) -{ - if (SECSuccess != ssl_SetTimeout(fd, timeout)) { - return SECFailure; - } - return SSL_ReHandshake(fd, flushCache); -} - -SECStatus -SSL_RedoHandshake(PRFileDesc *fd) -{ - return SSL_ReHandshake(fd, PR_TRUE); -} - -/* Register an application callback to be called when SSL handshake completes. -** Acquires and releases HandshakeLock. -*/ -SECStatus -SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb, - void *client_data) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeCallback", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (!ss->opt.useSecurity) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - ss->handshakeCallback = cb; - ss->handshakeCallbackData = client_data; - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return SECSuccess; -} - -/* Register an application callback to be called when false start may happen. -** Acquires and releases HandshakeLock. -*/ -SECStatus -SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, - void *arg) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (!ss->opt.useSecurity) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - ss->canFalseStartCallback = cb; - ss->canFalseStartCallbackData = arg; - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return SECSuccess; -} - -SECStatus -SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) -{ - sslSocket *ss; - - *canFalseStart = PR_FALSE; - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (!ss->ssl3.initialized) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (ss->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - return SECFailure; - } - - /* Require a forward-secret key exchange. */ - *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss || - ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || - ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || - ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa; - - return SECSuccess; -} - -/* Try to make progress on an SSL handshake by attempting to read the -** next handshake from the peer, and sending any responses. -** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot -** read the next handshake from the underlying socket. -** For SSLv2, returns when handshake is complete or fatal error occurs. -** For SSLv3, returns when handshake is complete, or application data has -** arrived that must be taken by application before handshake can continue, -** or a fatal error occurs. -** Application should use handshake completion callback to tell which. -*/ -SECStatus -SSL_ForceHandshake(PRFileDesc *fd) -{ - sslSocket *ss; - SECStatus rv = SECFailure; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake", - SSL_GETPID(), fd)); - return rv; - } - - /* Don't waste my time */ - if (!ss->opt.useSecurity) - return SECSuccess; - - if (!ssl_SocketIsBlocking(ss)) { - ssl_GetXmitBufLock(ss); - if (ss->pendingBuf.len != 0) { - int sent = ssl_SendSavedWriteData(ss); - if ((sent < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { - ssl_ReleaseXmitBufLock(ss); - return SECFailure; - } - } - ssl_ReleaseXmitBufLock(ss); - } - - ssl_Get1stHandshakeLock(ss); - - if (ss->version >= SSL_LIBRARY_VERSION_3_0) { - int gatherResult; - - ssl_GetRecvBufLock(ss); - gatherResult = ssl3_GatherCompleteHandshake(ss, 0); - ssl_ReleaseRecvBufLock(ss); - if (gatherResult > 0) { - rv = SECSuccess; - } else if (gatherResult == 0) { - PORT_SetError(PR_END_OF_FILE_ERROR); - } else if (gatherResult == SECWouldBlock) { - PORT_SetError(PR_WOULD_BLOCK_ERROR); - } - } else if (!ss->firstHsDone) { - rv = ssl_Do1stHandshake(ss); - } else { - /* tried to force handshake on an SSL 2 socket that has - ** already completed the handshake. */ - rv = SECSuccess; /* just pretend we did it. */ - } - - ssl_Release1stHandshakeLock(ss); - - return rv; -} - -/* - ** Same as above, but with an I/O timeout. - */ -SSL_IMPORT SECStatus -SSL_ForceHandshakeWithTimeout(PRFileDesc *fd, - PRIntervalTime timeout) -{ - if (SECSuccess != ssl_SetTimeout(fd, timeout)) { - return SECFailure; - } - return SSL_ForceHandshake(fd); -} - -/************************************************************************/ - -/* -** Grow a buffer to hold newLen bytes of data. -** Called for both recv buffers and xmit buffers. -** Caller must hold xmitBufLock or recvBufLock, as appropriate. -*/ -SECStatus -sslBuffer_Grow(sslBuffer *b, unsigned int newLen) -{ - newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048); - if (newLen > b->space) { - unsigned char *newBuf; - if (b->buf) { - newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen); - } else { - newBuf = (unsigned char *)PORT_Alloc(newLen); - } - if (!newBuf) { - return SECFailure; - } - SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d", - SSL_GETPID(), b->space, newLen)); - b->buf = newBuf; - b->space = newLen; - } - return SECSuccess; -} - -SECStatus -sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len) -{ - unsigned int newLen = b->len + len; - SECStatus rv; - - rv = sslBuffer_Grow(b, newLen); - if (rv != SECSuccess) - return rv; - PORT_Memcpy(b->buf + b->len, data, len); - b->len += len; - return SECSuccess; -} - -/* -** Save away write data that is trying to be written before the security -** handshake has been completed. When the handshake is completed, we will -** flush this data out. -** Caller must hold xmitBufLock -*/ -SECStatus -ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len) -{ - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - rv = sslBuffer_Append(&ss->pendingBuf, data, len); - SSL_TRC(5, ("%d: SSL[%d]: saving %u bytes of data (%u total saved so far)", - SSL_GETPID(), ss->fd, len, ss->pendingBuf.len)); - return rv; -} - -/* -** Send saved write data. This will flush out data sent prior to a -** complete security handshake. Hopefully there won't be too much of it. -** Returns count of the bytes sent, NOT a SECStatus. -** Caller must hold xmitBufLock -*/ -int -ssl_SendSavedWriteData(sslSocket *ss) -{ - int rv = 0; - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - if (ss->pendingBuf.len != 0) { - SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data", - SSL_GETPID(), ss->fd, ss->pendingBuf.len)); - rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0); - if (rv < 0) { - return rv; - } - ss->pendingBuf.len -= rv; - if (ss->pendingBuf.len > 0 && rv > 0) { - /* UGH !! This shifts the whole buffer down by copying it */ - PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv, - ss->pendingBuf.len); - } - } - return rv; -} - -/************************************************************************/ - -/* -** Receive some application data on a socket. Reads SSL records from the input -** stream, decrypts them and then copies them to the output buffer. -** Called from ssl_SecureRecv() below. -** -** Caller does NOT hold 1stHandshakeLock because that handshake is over. -** Caller doesn't call this until initial handshake is complete. -** For SSLv2, there is no subsequent handshake. -** For SSLv3, the call to ssl3_GatherAppDataRecord may encounter handshake -** messages from a subsequent handshake. -** -** This code is similar to, and easily confused with, -** ssl_GatherRecord1stHandshake() in sslcon.c -*/ -static int -DoRecv(sslSocket *ss, unsigned char *out, int len, int flags) -{ - int rv; - int amount; - int available; - - /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the - * 1stHandshakeLock. */ - ssl_Get1stHandshakeLock(ss); - ssl_GetRecvBufLock(ss); - - available = ss->gs.writeOffset - ss->gs.readOffset; - if (available == 0) { - /* Get some more data */ - if (ss->version >= SSL_LIBRARY_VERSION_3_0) { - /* Wait for application data to arrive. */ - rv = ssl3_GatherAppDataRecord(ss, 0); - } else { - /* See if we have a complete record */ - rv = ssl2_GatherRecord(ss, 0); - } - if (rv <= 0) { - if (rv == 0) { - /* EOF */ - SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF", - SSL_GETPID(), ss->fd)); - goto done; - } - if ((rv != SECWouldBlock) && - (PR_GetError() != PR_WOULD_BLOCK_ERROR)) { - /* Some random error */ - goto done; - } - - /* - ** Gather record is blocked waiting for more record data to - ** arrive. Try to process what we have already received - */ - } else { - /* Gather record has finished getting a complete record */ - } - - /* See if any clear data is now available */ - available = ss->gs.writeOffset - ss->gs.readOffset; - if (available == 0) { - /* - ** No partial data is available. Force error code to - ** EWOULDBLOCK so that caller will try again later. Note - ** that the error code is probably EWOULDBLOCK already, - ** but if it isn't (for example, if we received a zero - ** length record) then this will force it to be correct. - */ - PORT_SetError(PR_WOULD_BLOCK_ERROR); - rv = SECFailure; - goto done; - } - SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d", - SSL_GETPID(), ss->fd, available)); - } - - if (IS_DTLS(ss) && (len < available)) { - /* DTLS does not allow you to do partial reads */ - SSL_TRC(30, ("%d: SSL[%d]: DTLS short read. len=%d available=%d", - SSL_GETPID(), ss->fd, len, available)); - ss->gs.readOffset += available; - PORT_SetError(SSL_ERROR_RX_SHORT_DTLS_READ); - rv = SECFailure; - goto done; - } - - /* Dole out clear data to reader */ - amount = PR_MIN(len, available); - PORT_Memcpy(out, ss->gs.buf.buf + ss->gs.readOffset, amount); - if (!(flags & PR_MSG_PEEK)) { - ss->gs.readOffset += amount; - } - PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset); - rv = amount; - - SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d", - SSL_GETPID(), ss->fd, amount, available)); - PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount)); - -done: - ssl_ReleaseRecvBufLock(ss); - ssl_Release1stHandshakeLock(ss); - return rv; -} - -/************************************************************************/ - -/* -** Return SSLKEAType derived from cert's Public Key algorithm info. -*/ -SSLKEAType -NSS_FindCertKEAType(CERTCertificate *cert) -{ - SSLKEAType keaType = kt_null; - int tag; - - if (!cert) - goto loser; - - tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); - - switch (tag) { - case SEC_OID_X500_RSA_ENCRYPTION: - case SEC_OID_PKCS1_RSA_ENCRYPTION: - keaType = kt_rsa; - break; - case SEC_OID_ANSIX9_DSA_SIGNATURE: /* hah, signature, not a key? */ - case SEC_OID_X942_DIFFIE_HELMAN_KEY: - keaType = kt_dh; - break; -#ifndef NSS_DISABLE_ECC - case SEC_OID_ANSIX962_EC_PUBLIC_KEY: - keaType = kt_ecdh; - break; -#endif /* NSS_DISABLE_ECC */ - default: - keaType = kt_null; - } - -loser: - - return keaType; -} - -static const PRCallOnceType pristineCallOnce; -static PRCallOnceType setupServerCAListOnce; - -static SECStatus -serverCAListShutdown(void *appData, void *nssData) -{ - PORT_Assert(ssl3_server_ca_list); - if (ssl3_server_ca_list) { - CERT_FreeDistNames(ssl3_server_ca_list); - ssl3_server_ca_list = NULL; - } - setupServerCAListOnce = pristineCallOnce; - return SECSuccess; -} - -static PRStatus -serverCAListSetup(void *arg) -{ - CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg; - SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL); - PORT_Assert(SECSuccess == rv); - if (SECSuccess == rv) { - ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle); - return PR_SUCCESS; - } - return PR_FAILURE; -} - -SECStatus -ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert, - const CERTCertificateList *certChain, - ssl3KeyPair *keyPair, SSLKEAType kea) -{ - CERTCertificateList *localCertChain = NULL; - sslServerCerts *sc = ss->serverCerts + kea; - - /* load the server certificate */ - if (sc->serverCert != NULL) { - CERT_DestroyCertificate(sc->serverCert); - sc->serverCert = NULL; - sc->serverKeyBits = 0; - } - /* load the server cert chain */ - if (sc->serverCertChain != NULL) { - CERT_DestroyCertificateList(sc->serverCertChain); - sc->serverCertChain = NULL; - } - if (cert) { - sc->serverCert = CERT_DupCertificate(cert); - /* get the size of the cert's public key, and remember it */ - sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey); - if (!certChain) { - localCertChain = - CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer, - PR_TRUE); - if (!localCertChain) - goto loser; - } - sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) : - localCertChain; - if (!sc->serverCertChain) { - goto loser; - } - localCertChain = NULL; /* consumed */ - } - - /* get keyPair */ - if (sc->serverKeyPair != NULL) { - ssl3_FreeKeyPair(sc->serverKeyPair); - sc->serverKeyPair = NULL; - } - if (keyPair) { - SECKEY_CacheStaticFlags(keyPair->privKey); - sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair); - } - if (kea == kt_rsa && cert && sc->serverKeyBits > 512 && - !ss->opt.noStepDown && !ss->stepDownKeyPair) { - if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) { - goto loser; - } - } - if (kea == ssl_kea_dh || kea == ssl_kea_rsa) { - if (ssl3_SelectDHParams(ss) != SECSuccess) { - goto loser; - } - } - return SECSuccess; - -loser: - if (localCertChain) { - CERT_DestroyCertificateList(localCertChain); - } - if (sc->serverCert != NULL) { - CERT_DestroyCertificate(sc->serverCert); - sc->serverCert = NULL; - } - if (sc->serverCertChain != NULL) { - CERT_DestroyCertificateList(sc->serverCertChain); - sc->serverCertChain = NULL; - } - if (sc->serverKeyPair != NULL) { - ssl3_FreeKeyPair(sc->serverKeyPair); - sc->serverKeyPair = NULL; - } - return SECFailure; -} - -/* XXX need to protect the data that gets changed here.!! */ - -SECStatus -SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, - SECKEYPrivateKey *key, SSL3KEAType kea) -{ - - return SSL_ConfigSecureServerWithCertChain(fd, cert, NULL, key, kea); -} - -SECStatus -SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, - const CERTCertificateList *certChainOpt, - SECKEYPrivateKey *key, SSL3KEAType kea) -{ - sslSocket *ss; - SECKEYPublicKey *pubKey = NULL; - ssl3KeyPair *keyPair = NULL; - SECStatus rv = SECFailure; - - ss = ssl_FindSocket(fd); - if (!ss) { - return SECFailure; - } - - /* Both key and cert must have a value or be NULL */ - /* Passing a value of NULL will turn off key exchange algorithms that were - * previously turned on */ - if (!cert != !key) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - /* make sure the key exchange is recognized */ - if ((kea >= kt_kea_size) || (kea < kt_null)) { - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); - return SECFailure; - } - - if (kea != NSS_FindCertKEAType(cert)) { - PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH); - return SECFailure; - } - - if (cert) { - /* get the size of the cert's public key, and remember it */ - pubKey = CERT_ExtractPublicKey(cert); - if (!pubKey) - return SECFailure; - } - - if (key) { - SECKEYPrivateKey *keyCopy = NULL; - CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM; - - if (key->pkcs11Slot) { - PK11SlotInfo *bestSlot; - bestSlot = PK11_ReferenceSlot(key->pkcs11Slot); - if (bestSlot) { - keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); - PK11_FreeSlot(bestSlot); - } - } - if (keyCopy == NULL) - keyMech = PK11_MapSignKeyType(key->keyType); - if (keyMech != CKM_INVALID_MECHANISM) { - PK11SlotInfo *bestSlot; - /* XXX Maybe should be bestSlotMultiple? */ - bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */); - if (bestSlot) { - keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); - PK11_FreeSlot(bestSlot); - } - } - if (keyCopy == NULL) - keyCopy = SECKEY_CopyPrivateKey(key); - if (keyCopy == NULL) - goto loser; - keyPair = ssl3_NewKeyPair(keyCopy, pubKey); - if (keyPair == NULL) { - SECKEY_DestroyPrivateKey(keyCopy); - goto loser; - } - pubKey = NULL; /* adopted by serverKeyPair */ - } - if (ssl_ConfigSecureServer(ss, cert, certChainOpt, - keyPair, kea) == SECFailure) { - goto loser; - } - - /* Only do this once because it's global. */ - if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, - &serverCAListSetup, - (void *)(ss->dbHandle))) { - rv = SECSuccess; - } - -loser: - if (keyPair) { - ssl3_FreeKeyPair(keyPair); - } - if (pubKey) { - SECKEY_DestroyPublicKey(pubKey); - pubKey = NULL; - } - return rv; -} - -/************************************************************************/ - -SECStatus -ssl_CreateSecurityInfo(sslSocket *ss) -{ - SECStatus status; - - /* initialize sslv2 socket to send data in the clear. */ - ssl2_UseClearSendFunc(ss); - - ss->sec.blockSize = 1; - ss->sec.blockShift = 0; - - ssl_GetXmitBufLock(ss); - status = sslBuffer_Grow(&ss->sec.writeBuf, 4096); - ssl_ReleaseXmitBufLock(ss); - - return status; -} - -SECStatus -ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os) -{ - ss->sec.send = os->sec.send; - ss->sec.isServer = os->sec.isServer; - ss->sec.keyBits = os->sec.keyBits; - ss->sec.secretKeyBits = os->sec.secretKeyBits; - - ss->sec.peerCert = CERT_DupCertificate(os->sec.peerCert); - if (os->sec.peerCert && !ss->sec.peerCert) - goto loser; - - ss->sec.cache = os->sec.cache; - ss->sec.uncache = os->sec.uncache; - - /* we don't dup the connection info. */ - - ss->sec.sendSequence = os->sec.sendSequence; - ss->sec.rcvSequence = os->sec.rcvSequence; - - if (os->sec.hash && os->sec.hashcx) { - ss->sec.hash = os->sec.hash; - ss->sec.hashcx = os->sec.hash->clone(os->sec.hashcx); - if (os->sec.hashcx && !ss->sec.hashcx) - goto loser; - } else { - ss->sec.hash = NULL; - ss->sec.hashcx = NULL; - } - - if (SECITEM_CopyItem(0, &ss->sec.sendSecret, &os->sec.sendSecret)) - goto loser; - if (SECITEM_CopyItem(0, &ss->sec.rcvSecret, &os->sec.rcvSecret)) - goto loser; - - /* XXX following code is wrong if either cx != 0 */ - PORT_Assert(os->sec.readcx == 0); - PORT_Assert(os->sec.writecx == 0); - ss->sec.readcx = os->sec.readcx; - ss->sec.writecx = os->sec.writecx; - ss->sec.destroy = 0; - - ss->sec.enc = os->sec.enc; - ss->sec.dec = os->sec.dec; - - ss->sec.blockShift = os->sec.blockShift; - ss->sec.blockSize = os->sec.blockSize; - - return SECSuccess; - -loser: - return SECFailure; -} - -/* Reset sec back to its initial state. -** Caller holds any relevant locks. -*/ -void -ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset) -{ - /* Destroy MAC */ - if (sec->hash && sec->hashcx) { - (*sec->hash->destroy)(sec->hashcx, PR_TRUE); - sec->hashcx = NULL; - sec->hash = NULL; - } - SECITEM_ZfreeItem(&sec->sendSecret, PR_FALSE); - SECITEM_ZfreeItem(&sec->rcvSecret, PR_FALSE); - - /* Destroy ciphers */ - if (sec->destroy) { - (*sec->destroy)(sec->readcx, PR_TRUE); - (*sec->destroy)(sec->writecx, PR_TRUE); - sec->readcx = NULL; - sec->writecx = NULL; - } else { - PORT_Assert(sec->readcx == 0); - PORT_Assert(sec->writecx == 0); - } - sec->readcx = 0; - sec->writecx = 0; - - if (sec->localCert) { - CERT_DestroyCertificate(sec->localCert); - sec->localCert = NULL; - } - if (sec->peerCert) { - CERT_DestroyCertificate(sec->peerCert); - sec->peerCert = NULL; - } - if (sec->peerKey) { - SECKEY_DestroyPublicKey(sec->peerKey); - sec->peerKey = NULL; - } - - /* cleanup the ci */ - if (sec->ci.sid != NULL) { - ssl_FreeSID(sec->ci.sid); - } - PORT_ZFree(sec->ci.sendBuf.buf, sec->ci.sendBuf.space); - if (doMemset) { - memset(&sec->ci, 0, sizeof sec->ci); - } -} - -/* -** Called from SSL_ResetHandshake (above), and -** from ssl_FreeSocket in sslsock.c -** Caller should hold relevant locks (e.g. XmitBufLock) -*/ -void -ssl_DestroySecurityInfo(sslSecurityInfo *sec) -{ - ssl_ResetSecurityInfo(sec, PR_FALSE); - - PORT_ZFree(sec->writeBuf.buf, sec->writeBuf.space); - sec->writeBuf.buf = 0; - - memset(sec, 0, sizeof *sec); -} - -/************************************************************************/ - -int -ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa) -{ - PRFileDesc *osfd = ss->fd->lower; - int rv; - - if (ss->opt.handshakeAsServer) { - ss->securityHandshake = ssl2_BeginServerHandshake; - ss->handshaking = sslHandshakingAsServer; - } else { - ss->securityHandshake = ssl2_BeginClientHandshake; - ss->handshaking = sslHandshakingAsClient; - } - - /* connect to server */ - rv = osfd->methods->connect(osfd, sa, ss->cTimeout); - if (rv == PR_SUCCESS) { - ss->TCPconnected = 1; - } else { - int err = PR_GetError(); - SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d", - SSL_GETPID(), ss->fd, err)); - if (err == PR_IS_CONNECTED_ERROR) { - ss->TCPconnected = 1; - } - } - - SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, rv == %d", - SSL_GETPID(), ss->fd, rv)); - return rv; -} - -/* - * The TLS 1.2 RFC 5246, Section 7.2.1 says: - * - * Unless some other fatal alert has been transmitted, each party is - * required to send a close_notify alert before closing the write side - * of the connection. The other party MUST respond with a close_notify - * alert of its own and close down the connection immediately, - * discarding any pending writes. It is not required for the initiator - * of the close to wait for the responding close_notify alert before - * closing the read side of the connection. - * - * The second sentence requires that we send a close_notify alert when we - * have received a close_notify alert. In practice, all SSL implementations - * close the socket immediately after sending a close_notify alert (which is - * allowed by the third sentence), so responding with a close_notify alert - * would result in a write failure with the ECONNRESET error. This is why - * we don't respond with a close_notify alert. - * - * Also, in the unlikely event that the TCP pipe is full and the peer stops - * reading, the SSL3_SendAlert call in ssl_SecureClose and ssl_SecureShutdown - * may block indefinitely in blocking mode, and may fail (without retrying) - * in non-blocking mode. - */ - -int -ssl_SecureClose(sslSocket *ss) -{ - int rv; - - if (ss->version >= SSL_LIBRARY_VERSION_3_0 && - !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && - ss->firstHsDone && - !ss->recvdCloseNotify && - ss->ssl3.initialized) { - - /* We don't want the final alert to be Nagle delayed. */ - if (!ss->delayDisabled) { - ssl_EnableNagleDelay(ss, PR_FALSE); - ss->delayDisabled = 1; - } - - (void)SSL3_SendAlert(ss, alert_warning, close_notify); - } - rv = ssl_DefClose(ss); - return rv; -} - -/* Caller handles all locking */ -int -ssl_SecureShutdown(sslSocket *ss, int nsprHow) -{ - PRFileDesc *osfd = ss->fd->lower; - int rv; - PRIntn sslHow = nsprHow + 1; - - if ((unsigned)nsprHow > PR_SHUTDOWN_BOTH) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return PR_FAILURE; - } - - if ((sslHow & ssl_SHUTDOWN_SEND) != 0 && - ss->version >= SSL_LIBRARY_VERSION_3_0 && - !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && - ss->firstHsDone && - !ss->recvdCloseNotify && - ss->ssl3.initialized) { - - (void)SSL3_SendAlert(ss, alert_warning, close_notify); - } - - rv = osfd->methods->shutdown(osfd, nsprHow); - - ss->shutdownHow |= sslHow; - - return rv; -} - -/************************************************************************/ - -int -ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) -{ - int rv = 0; - - if (ss->shutdownHow & ssl_SHUTDOWN_RCV) { - PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); - return PR_FAILURE; - } - if (flags & ~PR_MSG_PEEK) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return PR_FAILURE; - } - - if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) { - ssl_GetXmitBufLock(ss); - if (ss->pendingBuf.len != 0) { - rv = ssl_SendSavedWriteData(ss); - if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { - ssl_ReleaseXmitBufLock(ss); - return SECFailure; - } - } - ssl_ReleaseXmitBufLock(ss); - } - - rv = 0; - /* If any of these is non-zero, the initial handshake is not done. */ - if (!ss->firstHsDone) { - ssl_Get1stHandshakeLock(ss); - if (ss->handshake || ss->nextHandshake || ss->securityHandshake) { - rv = ssl_Do1stHandshake(ss); - } - ssl_Release1stHandshakeLock(ss); - } - if (rv < 0) { - return rv; - } - - if (len == 0) - return 0; - - rv = DoRecv(ss, (unsigned char *)buf, len, flags); - SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes securely (errno=%d)", - SSL_GETPID(), ss->fd, rv, PORT_GetError())); - return rv; -} - -int -ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len) -{ - return ssl_SecureRecv(ss, buf, len, 0); -} - -/* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */ -int -ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) -{ - int rv = 0; - - SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", - SSL_GETPID(), ss->fd, len)); - - if (ss->shutdownHow & ssl_SHUTDOWN_SEND) { - PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); - rv = PR_FAILURE; - goto done; - } - if (flags) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - rv = PR_FAILURE; - goto done; - } - - ssl_GetXmitBufLock(ss); - if (ss->pendingBuf.len != 0) { - PORT_Assert(ss->pendingBuf.len > 0); - rv = ssl_SendSavedWriteData(ss); - if (rv >= 0 && ss->pendingBuf.len != 0) { - PORT_Assert(ss->pendingBuf.len > 0); - PORT_SetError(PR_WOULD_BLOCK_ERROR); - rv = SECFailure; - } - } - ssl_ReleaseXmitBufLock(ss); - if (rv < 0) { - goto done; - } - - if (len > 0) - ss->writerThread = PR_GetCurrentThread(); - /* If any of these is non-zero, the initial handshake is not done. */ - if (!ss->firstHsDone) { - PRBool falseStart = PR_FALSE; - ssl_Get1stHandshakeLock(ss); - if (ss->opt.enableFalseStart && - ss->version >= SSL_LIBRARY_VERSION_3_0) { - ssl_GetSSL3HandshakeLock(ss); - falseStart = ss->ssl3.hs.canFalseStart; - ssl_ReleaseSSL3HandshakeLock(ss); - } - if (!falseStart && - (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { - rv = ssl_Do1stHandshake(ss); - } - ssl_Release1stHandshakeLock(ss); - } - if (rv < 0) { - ss->writerThread = NULL; - goto done; - } - - /* Check for zero length writes after we do housekeeping so we make forward - * progress. - */ - if (len == 0) { - rv = 0; - goto done; - } - PORT_Assert(buf != NULL); - if (!buf) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - rv = PR_FAILURE; - goto done; - } - - if (!ss->firstHsDone) { - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0); -#ifdef DEBUG - ssl_GetSSL3HandshakeLock(ss); - PORT_Assert(ss->ssl3.hs.canFalseStart); - ssl_ReleaseSSL3HandshakeLock(ss); -#endif - SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", - SSL_GETPID(), ss->fd)); - } - - /* Send out the data using one of these functions: - * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, - * ssl3_SendApplicationData - */ - ssl_GetXmitBufLock(ss); - rv = (*ss->sec.send)(ss, buf, len, flags); - ssl_ReleaseXmitBufLock(ss); - ss->writerThread = NULL; -done: - if (rv < 0) { - SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d", - SSL_GETPID(), ss->fd, rv, PORT_GetError())); - } else { - SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count", - SSL_GETPID(), ss->fd, rv)); - } - return rv; -} - -int -ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len) -{ - return ssl_SecureSend(ss, buf, len, 0); -} - -SECStatus -SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSLBadCertHook", - SSL_GETPID(), fd)); - return SECFailure; - } - - ss->handleBadCert = f; - ss->badCertArg = arg; - - return SECSuccess; -} - -/* - * Allow the application to pass the url or hostname into the SSL library - * so that we can do some checking on it. It will be used for the value in - * SNI extension of client hello message. - */ -SECStatus -SSL_SetURL(PRFileDesc *fd, const char *url) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECSuccess; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSLSetURL", - SSL_GETPID(), fd)); - return SECFailure; - } - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (ss->url) { - PORT_Free((void *)ss->url); /* CONST */ - } - - ss->url = (const char *)PORT_Strdup(url); - if (ss->url == NULL) { - rv = SECFailure; - } - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return rv; -} - -/* - * Allow the application to pass the set of trust anchors - */ -SECStatus -SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList) -{ - sslSocket *ss = ssl_FindSocket(fd); - CERTDistNames *names = NULL; - - if (!certList) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors", - SSL_GETPID(), fd)); - return SECFailure; - } - - names = CERT_DistNamesFromCertList(certList); - if (names == NULL) { - return SECFailure; - } - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - if (ss->ssl3.ca_list) { - CERT_FreeDistNames(ss->ssl3.ca_list); - } - ss->ssl3.ca_list = names; - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return SECSuccess; -} - -/* -** Returns Negative number on error, zero or greater on success. -** Returns the amount of data immediately available to be read. -*/ -int -SSL_DataPending(PRFileDesc *fd) -{ - sslSocket *ss; - int rv = 0; - - ss = ssl_FindSocket(fd); - - if (ss && ss->opt.useSecurity) { - ssl_GetRecvBufLock(ss); - rv = ss->gs.writeOffset - ss->gs.readOffset; - ssl_ReleaseRecvBufLock(ss); - } - - return rv; -} - -SECStatus -SSL_InvalidateSession(PRFileDesc *fd) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECFailure; - - if (ss) { - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (ss->sec.ci.sid && ss->sec.uncache) { - ss->sec.uncache(ss->sec.ci.sid); - rv = SECSuccess; - } - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - } - return rv; -} - -static void -ssl3_CacheSessionUnlocked(sslSocket *ss) -{ - PORT_Assert(!ss->sec.isServer); - - if (ss->ssl3.hs.cacheSID) { - ss->sec.cache(ss->sec.ci.sid); - ss->ssl3.hs.cacheSID = PR_FALSE; - } -} - -SECStatus -SSL_CacheSession(PRFileDesc *fd) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECFailure; - - if (ss) { - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - ssl3_CacheSessionUnlocked(ss); - rv = SECSuccess; - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - } - return rv; -} - -SECStatus -SSL_CacheSessionUnlocked(PRFileDesc *fd) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECFailure; - - if (ss) { - ssl3_CacheSessionUnlocked(ss); - rv = SECSuccess; - } - return rv; -} - -SECItem * -SSL_GetSessionID(PRFileDesc *fd) -{ - sslSocket *ss; - SECItem *item = NULL; - - ss = ssl_FindSocket(fd); - if (ss) { - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (ss->opt.useSecurity && ss->firstHsDone && ss->sec.ci.sid) { - item = (SECItem *)PORT_Alloc(sizeof(SECItem)); - if (item) { - sslSessionID *sid = ss->sec.ci.sid; - if (sid->version < SSL_LIBRARY_VERSION_3_0) { - item->len = SSL2_SESSIONID_BYTES; - item->data = (unsigned char *)PORT_Alloc(item->len); - PORT_Memcpy(item->data, sid->u.ssl2.sessionID, item->len); - } else { - item->len = sid->u.ssl3.sessionIDLength; - item->data = (unsigned char *)PORT_Alloc(item->len); - PORT_Memcpy(item->data, sid->u.ssl3.sessionID, item->len); - } - } - } - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - } - return item; -} - -SECStatus -SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) - return SECFailure; - if (!dbHandle) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - ss->dbHandle = dbHandle; - return SECSuccess; -} - -/* - * attempt to restart the handshake after asynchronously handling - * a request for the client's certificate. - * - * inputs: - * cert Client cert chosen by application. - * Note: ssl takes this reference, and does not bump the - * reference count. The caller should drop its reference - * without calling CERT_DestroyCertificate after calling this - * function. - * - * key Private key associated with cert. This function takes - * ownership of the private key, so the caller should drop its - * reference without destroying the private key after this - * function returns. - * - * certChain Chain of signers for cert. - * Note: ssl takes this reference, and does not copy the chain. - * The caller should drop its reference without destroying the - * chain. SSL will free the chain when it is done with it. - * - * Return value: XXX - * - * XXX This code only works on the initial handshake on a connection, XXX - * It does not work on a subsequent handshake (redo). - */ -SECStatus -SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus ret; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterCertReq", - SSL_GETPID(), fd)); - if (cert) { - CERT_DestroyCertificate(cert); - } - if (key) { - SECKEY_DestroyPrivateKey(key); - } - if (certChain) { - CERT_DestroyCertificateList(certChain); - } - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); /************************************/ - - if (ss->version >= SSL_LIBRARY_VERSION_3_0) { - ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain); - } else { - if (certChain != NULL) { - CERT_DestroyCertificateList(certChain); - } - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - ret = SECFailure; - } - - ssl_Release1stHandshakeLock(ss); /************************************/ - return ret; -} - -SECStatus -SSL_RestartHandshakeAfterChannelIDReq(PRFileDesc *fd, - SECKEYPublicKey *channelIDPub, - SECKEYPrivateKey *channelID) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus ret; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in" - " SSL_RestartHandshakeAfterChannelIDReq", - SSL_GETPID(), fd)); - goto loser; - } - - ssl_Get1stHandshakeLock(ss); - - if (ss->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - ssl_Release1stHandshakeLock(ss); - goto loser; - } - - ret = ssl3_RestartHandshakeAfterChannelIDReq(ss, channelIDPub, - channelID); - ssl_Release1stHandshakeLock(ss); - - return ret; - -loser: - SECKEY_DestroyPublicKey(channelIDPub); - SECKEY_DestroyPrivateKey(channelID); - return SECFailure; -} - -/* DO NOT USE. This function was exported in ssl.def with the wrong signature; - * this implementation exists to maintain link-time compatibility. - */ -int -SSL_RestartHandshakeAfterServerCert(sslSocket *ss) -{ - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return -1; -} - -/* See documentation in ssl.h */ -SECStatus -SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error) -{ - SECStatus rv; - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_AuthCertificateComplete", - SSL_GETPID(), fd)); - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - - if (!ss->ssl3.initialized) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } else if (ss->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - rv = SECFailure; - } else { - rv = ssl3_AuthCertificateComplete(ss, error); - } - - ssl_Release1stHandshakeLock(ss); - - return rv; -} - -/* For more info see ssl.h */ -SECStatus -SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func, - void *arg) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook", - SSL_GETPID(), fd)); - return SECFailure; - } - - ss->sniSocketConfig = func; - ss->sniSocketConfigArg = arg; - return SECSuccess; -}
diff --git a/net/third_party/nss/ssl/sslsnce.c b/net/third_party/nss/ssl/sslsnce.c deleted file mode 100644 index e3f749e5..0000000 --- a/net/third_party/nss/ssl/sslsnce.c +++ /dev/null
@@ -1,2204 +0,0 @@ -/* This file implements the SERVER Session ID cache. - * NOTE: The contents of this file are NOT used by the client. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server - * cache sids! - * - * About record locking among different server processes: - * - * All processes that are part of the same conceptual server (serving on - * the same address and port) MUST share a common SSL session cache. - * This code makes the content of the shared cache accessible to all - * processes on the same "server". This code works on Unix and Win32 only. - * - * We use NSPR anonymous shared memory and move data to & from shared memory. - * We must do explicit locking of the records for all reads and writes. - * The set of Cache entries are divided up into "sets" of 128 entries. - * Each set is protected by a lock. There may be one or more sets protected - * by each lock. That is, locks to sets are 1:N. - * There is one lock for the entire cert cache. - * There is one lock for the set of wrapped sym wrap keys. - * - * The anonymous shared memory is laid out as if it were declared like this: - * - * struct { - * cacheDescriptor desc; - * sidCacheLock sidCacheLocks[ numSIDCacheLocks]; - * sidCacheLock keyCacheLock; - * sidCacheLock certCacheLock; - * sidCacheSet sidCacheSets[ numSIDCacheSets ]; - * sidCacheEntry sidCacheData[ numSIDCacheEntries]; - * certCacheEntry certCacheData[numCertCacheEntries]; - * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; - * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] - * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode - * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode - * PRBool ticketKeysValid; - * sidCacheLock srvNameCacheLock; - * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ]; - * } cacheMemCacheData; - */ -#include "seccomon.h" - -#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2) || defined(XP_BEOS) - -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "pk11func.h" -#include "base64.h" -#include "keyhi.h" -#ifdef NO_PKCS11_BYPASS -#include "blapit.h" -#include "sechash.h" -#else -#include "blapi.h" -#endif - -#include <stdio.h> - -#if defined(XP_UNIX) || defined(XP_BEOS) - -#include <syslog.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include "unix_err.h" - -#else - -#ifdef XP_WIN32 -#include <wtypes.h> -#include "win32err.h" -#endif - -#endif -#include <sys/types.h> - -#define SET_ERROR_CODE /* reminder */ - -#include "nspr.h" -#include "sslmutex.h" - -/* -** Format of a cache entry in the shared memory. -*/ -struct sidCacheEntryStr { - /* 16 */ PRIPv6Addr addr; /* client's IP address */ - /* 4 */ PRUint32 creationTime; - /* 4 */ PRUint32 lastAccessTime; - /* 4 */ PRUint32 expirationTime; - /* 2 */ PRUint16 version; - /* 1 */ PRUint8 valid; - /* 1 */ PRUint8 sessionIDLength; - /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; - /* 2 */ PRUint16 authAlgorithm; - /* 2 */ PRUint16 authKeyBits; - /* 2 */ PRUint16 keaType; - /* 2 */ PRUint16 keaKeyBits; - /* 72 - common header total */ - - union { - struct { - /* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES]; - /* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; - - /* 1 */ PRUint8 cipherType; - /* 1 */ PRUint8 masterKeyLen; - /* 1 */ PRUint8 keyBits; - /* 1 */ PRUint8 secretKeyBits; - /* 1 */ PRUint8 cipherArgLen; -/*101 */} ssl2; - -struct { - /* 2 */ ssl3CipherSuite cipherSuite; - /* 2 */ PRUint16 compression; /* SSLCompressionMethod */ - - /* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ - - /* 4 */ PRUint32 masterWrapMech; - /* 4 */ SSL3KEAType exchKeyType; - /* 4 */ PRInt32 certIndex; - /* 4 */ PRInt32 srvNameIndex; - /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ -/*108 */} ssl3; - -/* force sizeof(sidCacheEntry) to be a multiple of cache line size */ -struct { - /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */ -} forceSize; - } u; -}; -typedef struct sidCacheEntryStr sidCacheEntry; - -/* The length of this struct is supposed to be a power of 2, e.g. 4KB */ -struct certCacheEntryStr { - PRUint16 certLength; /* 2 */ - PRUint16 sessionIDLength; /* 2 */ - PRUint8 sessionID[SSL3_SESSIONID_BYTES]; /* 32 */ - PRUint8 cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */ -}; /* total 4096 */ -typedef struct certCacheEntryStr certCacheEntry; - -struct sidCacheLockStr { - PRUint32 timeStamp; - sslMutex mutex; - sslPID pid; -}; -typedef struct sidCacheLockStr sidCacheLock; - -struct sidCacheSetStr { - PRIntn next; -}; -typedef struct sidCacheSetStr sidCacheSet; - -struct encKeyCacheEntryStr { - PRUint8 bytes[512]; - PRInt32 length; -}; -typedef struct encKeyCacheEntryStr encKeyCacheEntry; - -#define SSL_MAX_DNS_HOST_NAME 1024 - -struct srvNameCacheEntryStr { - PRUint16 type; /* 2 */ - PRUint16 nameLen; /* 2 */ - PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */ - PRUint8 nameHash[SHA256_LENGTH]; /* 32 */ - /* 1072 */ -}; -typedef struct srvNameCacheEntryStr srvNameCacheEntry; - -struct cacheDescStr { - - PRUint32 cacheMemSize; - - PRUint32 numSIDCacheLocks; - PRUint32 numSIDCacheSets; - PRUint32 numSIDCacheSetsPerLock; - - PRUint32 numSIDCacheEntries; - PRUint32 sidCacheSize; - - PRUint32 numCertCacheEntries; - PRUint32 certCacheSize; - - PRUint32 numKeyCacheEntries; - PRUint32 keyCacheSize; - - PRUint32 numSrvNameCacheEntries; - PRUint32 srvNameCacheSize; - - PRUint32 ssl2Timeout; - PRUint32 ssl3Timeout; - - PRUint32 numSIDCacheLocksInitialized; - - /* These values are volatile, and are accessed through sharedCache-> */ - PRUint32 nextCertCacheEntry; /* certCacheLock protects */ - PRBool stopPolling; - PRBool everInherited; - - /* The private copies of these values are pointers into shared mem */ - /* The copies of these values in shared memory are merely offsets */ - sidCacheLock *sidCacheLocks; - sidCacheLock *keyCacheLock; - sidCacheLock *certCacheLock; - sidCacheLock *srvNameCacheLock; - sidCacheSet *sidCacheSets; - sidCacheEntry *sidCacheData; - certCacheEntry *certCacheData; - SSLWrappedSymWrappingKey *keyCacheData; - PRUint8 *ticketKeyNameSuffix; - encKeyCacheEntry *ticketEncKey; - encKeyCacheEntry *ticketMacKey; - PRUint32 *ticketKeysValid; - srvNameCacheEntry *srvNameCacheData; - - /* Only the private copies of these pointers are valid */ - char *cacheMem; - struct cacheDescStr *sharedCache; /* shared copy of this struct */ - PRFileMap *cacheMemMap; - PRThread *poller; - PRUint32 mutexTimeout; - PRBool shared; -}; -typedef struct cacheDescStr cacheDesc; - -static cacheDesc globalCache; - -static const char envVarName[] = { SSL_ENV_VAR_NAME }; - -static PRBool isMultiProcess = PR_FALSE; - -#define DEF_SID_CACHE_ENTRIES 10000 -#define DEF_CERT_CACHE_ENTRIES 250 -#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ -#define DEF_KEY_CACHE_ENTRIES 250 -#define DEF_NAME_CACHE_ENTRIES 1000 - -#define SID_CACHE_ENTRIES_PER_SET 128 -#define SID_ALIGNMENT 16 - -#define DEF_SSL2_TIMEOUT 100 /* seconds */ -#define MAX_SSL2_TIMEOUT 100 /* seconds */ -#define MIN_SSL2_TIMEOUT 5 /* seconds */ - -#define DEF_SSL3_TIMEOUT 86400L /* 24 hours */ -#define MAX_SSL3_TIMEOUT 86400L /* 24 hours */ -#define MIN_SSL3_TIMEOUT 5 /* seconds */ - -#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD) -#define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */ -#elif defined(OSF1) -#define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */ -#else -#define MAX_SID_CACHE_LOCKS 256 -#endif - -#define SID_HOWMANY(val, size) (((val) + ((size)-1)) / (size)) -#define SID_ROUNDUP(val, size) ((size)*SID_HOWMANY((val), (size))) - -static sslPID myPid; -static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS; - -/* forward static function declarations */ -static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, - unsigned nl); -static SECStatus LaunchLockPoller(cacheDesc *cache); -static SECStatus StopLockPoller(cacheDesc *cache); - -struct inheritanceStr { - PRUint32 cacheMemSize; - PRUint32 fmStrLen; -}; - -typedef struct inheritanceStr inheritance; - -#if defined(_WIN32) || defined(XP_OS2) - -#define DEFAULT_CACHE_DIRECTORY "\\temp" - -#endif /* _win32 */ - -#if defined(XP_UNIX) || defined(XP_BEOS) - -#define DEFAULT_CACHE_DIRECTORY "/tmp" - -#endif /* XP_UNIX || XP_BEOS */ - -/************************************************************************/ - -static PRUint32 -LockSidCacheLock(sidCacheLock *lock, PRUint32 now) -{ - SECStatus rv = sslMutex_Lock(&lock->mutex); - if (rv != SECSuccess) - return 0; - if (!now) - now = ssl_Time(); - lock->timeStamp = now; - lock->pid = myPid; - return now; -} - -static SECStatus -UnlockSidCacheLock(sidCacheLock *lock) -{ - SECStatus rv; - - lock->pid = 0; - rv = sslMutex_Unlock(&lock->mutex); - return rv; -} - -/* returns the value of ssl_Time on success, zero on failure. */ -static PRUint32 -LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now) -{ - PRUint32 lockNum = set % cache->numSIDCacheLocks; - sidCacheLock *lock = cache->sidCacheLocks + lockNum; - - return LockSidCacheLock(lock, now); -} - -static SECStatus -UnlockSet(cacheDesc *cache, PRUint32 set) -{ - PRUint32 lockNum = set % cache->numSIDCacheLocks; - sidCacheLock *lock = cache->sidCacheLocks + lockNum; - - return UnlockSidCacheLock(lock); -} - -/************************************************************************/ - -/* Put a certificate in the cache. Update the cert index in the sce. -*/ -static PRUint32 -CacheCert(cacheDesc *cache, CERTCertificate *cert, sidCacheEntry *sce) -{ - PRUint32 now; - certCacheEntry cce; - - if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) || - (cert->derCert.len <= 0) || - (cert->derCert.data == NULL)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return 0; - } - - cce.sessionIDLength = sce->sessionIDLength; - PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength); - - cce.certLength = cert->derCert.len; - PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength); - - /* get lock on cert cache */ - now = LockSidCacheLock(cache->certCacheLock, 0); - if (now) { - - /* Find where to place the next cert cache entry. */ - cacheDesc *sharedCache = cache->sharedCache; - PRUint32 ndx = sharedCache->nextCertCacheEntry; - - /* write the entry */ - cache->certCacheData[ndx] = cce; - - /* remember where we put it. */ - sce->u.ssl3.certIndex = ndx; - - /* update the "next" cache entry index */ - sharedCache->nextCertCacheEntry = - (ndx + 1) % cache->numCertCacheEntries; - - UnlockSidCacheLock(cache->certCacheLock); - } - return now; -} - -/* Server configuration hash tables need to account the SECITEM.type - * field as well. These functions accomplish that. */ -static PLHashNumber -Get32BitNameHash(const SECItem *name) -{ - PLHashNumber rv = SECITEM_Hash(name); - - PRUint8 *rvc = (PRUint8 *)&rv; - rvc[name->len % sizeof(rv)] ^= name->type; - - return rv; -} - -/* Put a name in the cache. Update the cert index in the sce. -*/ -static PRUint32 -CacheSrvName(cacheDesc *cache, SECItem *name, sidCacheEntry *sce) -{ - PRUint32 now; - PRUint32 ndx; - srvNameCacheEntry snce; - - if (!name || name->len <= 0 || - name->len > SSL_MAX_DNS_HOST_NAME) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return 0; - } - - snce.type = name->type; - snce.nameLen = name->len; - PORT_Memcpy(snce.name, name->data, snce.nameLen); -#ifdef NO_PKCS11_BYPASS - HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len); -#else - SHA256_HashBuf(snce.nameHash, (unsigned char *)name->data, - name->len); -#endif - /* get index of the next name */ - ndx = Get32BitNameHash(name); - /* get lock on cert cache */ - now = LockSidCacheLock(cache->srvNameCacheLock, 0); - if (now) { - if (cache->numSrvNameCacheEntries > 0) { - /* Fit the index into array */ - ndx %= cache->numSrvNameCacheEntries; - /* write the entry */ - cache->srvNameCacheData[ndx] = snce; - /* remember where we put it. */ - sce->u.ssl3.srvNameIndex = ndx; - /* Copy hash into sid hash */ - PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH); - } - UnlockSidCacheLock(cache->srvNameCacheLock); - } - return now; -} - -/* -** Convert local SID to shared memory one -*/ -static void -ConvertFromSID(sidCacheEntry *to, sslSessionID *from) -{ - to->valid = 1; - to->version = from->version; - to->addr = from->addr; - to->creationTime = from->creationTime; - to->lastAccessTime = from->lastAccessTime; - to->expirationTime = from->expirationTime; - to->authAlgorithm = from->authAlgorithm; - to->authKeyBits = from->authKeyBits; - to->keaType = from->keaType; - to->keaKeyBits = from->keaKeyBits; - - if (from->version < SSL_LIBRARY_VERSION_3_0) { - if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) || - (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) { - SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d", - myPid, from->u.ssl2.masterKey.len, - from->u.ssl2.cipherArg.len)); - to->valid = 0; - return; - } - - to->u.ssl2.cipherType = from->u.ssl2.cipherType; - to->u.ssl2.masterKeyLen = from->u.ssl2.masterKey.len; - to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len; - to->u.ssl2.keyBits = from->u.ssl2.keyBits; - to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; - to->sessionIDLength = SSL2_SESSIONID_BYTES; - PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES); - PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data, - from->u.ssl2.masterKey.len); - PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data, - from->u.ssl2.cipherArg.len); -#ifdef DEBUG - PORT_Memset(to->u.ssl2.masterKey + from->u.ssl2.masterKey.len, 0, - sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len); - PORT_Memset(to->u.ssl2.cipherArg + from->u.ssl2.cipherArg.len, 0, - sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len); -#endif - SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d " - "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", - myPid, - to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen, - to->creationTime, to->addr.pr_s6_addr32[0], - to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], - to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType)); - } else { - /* This is an SSL v3 session */ - - to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; - to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression; - to->u.ssl3.keys = from->u.ssl3.keys; - to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; - to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; - to->sessionIDLength = from->u.ssl3.sessionIDLength; - to->u.ssl3.certIndex = -1; - to->u.ssl3.srvNameIndex = -1; - PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID, - to->sessionIDLength); - - SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " - "cipherSuite=%d", - myPid, to->creationTime, to->addr.pr_s6_addr32[0], - to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], - to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite)); - } -} - -/* -** Convert shared memory cache-entry to local memory based one -** This is only called from ServerSessionIDLookup(). -*/ -static sslSessionID * -ConvertToSID(sidCacheEntry *from, - certCacheEntry *pcce, - srvNameCacheEntry *psnce, - CERTCertDBHandle *dbHandle) -{ - sslSessionID *to; - PRUint16 version = from->version; - - to = PORT_ZNew(sslSessionID); - if (!to) { - return 0; - } - - if (version < SSL_LIBRARY_VERSION_3_0) { - /* This is an SSL v2 session */ - to->u.ssl2.masterKey.data = - (unsigned char *)PORT_Alloc(from->u.ssl2.masterKeyLen); - if (!to->u.ssl2.masterKey.data) { - goto loser; - } - if (from->u.ssl2.cipherArgLen) { - to->u.ssl2.cipherArg.data = - (unsigned char *)PORT_Alloc(from->u.ssl2.cipherArgLen); - if (!to->u.ssl2.cipherArg.data) { - goto loser; - } - PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg, - from->u.ssl2.cipherArgLen); - } - - to->u.ssl2.cipherType = from->u.ssl2.cipherType; - to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen; - to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen; - to->u.ssl2.keyBits = from->u.ssl2.keyBits; - to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; - /* to->sessionIDLength = SSL2_SESSIONID_BYTES; */ - PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES); - PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey, - from->u.ssl2.masterKeyLen); - - SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d " - "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", - myPid, to->u.ssl2.masterKey.len, - to->u.ssl2.cipherArg.len, to->creationTime, - to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], - to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], - to->u.ssl2.cipherType)); - } else { - /* This is an SSL v3 session */ - - to->u.ssl3.sessionIDLength = from->sessionIDLength; - to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; - to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression; - to->u.ssl3.keys = from->u.ssl3.keys; - to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; - to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; - if (from->u.ssl3.srvNameIndex != -1 && psnce) { - SECItem name; - SECStatus rv; - name.type = psnce->type; - name.len = psnce->nameLen; - name.data = psnce->name; - rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name); - if (rv != SECSuccess) { - goto loser; - } - } - - PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength); - - /* the portions of the SID that are only restored on the client - * are set to invalid values on the server. - */ - to->u.ssl3.clientWriteKey = NULL; - to->u.ssl3.serverWriteKey = NULL; - - to->urlSvrName = NULL; - - to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */ - to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */ - to->u.ssl3.masterWrapIndex = 0; - to->u.ssl3.masterWrapSeries = 0; - to->u.ssl3.masterValid = PR_FALSE; - - to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */ - to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */ - to->u.ssl3.clAuthSeries = 0; - to->u.ssl3.clAuthValid = PR_FALSE; - - if (from->u.ssl3.certIndex != -1 && pcce) { - SECItem derCert; - - derCert.len = pcce->certLength; - derCert.data = pcce->cert; - - to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL, - PR_FALSE, PR_TRUE); - if (to->peerCert == NULL) - goto loser; - } - } - - to->version = from->version; - to->creationTime = from->creationTime; - to->lastAccessTime = from->lastAccessTime; - to->expirationTime = from->expirationTime; - to->cached = in_server_cache; - to->addr = from->addr; - to->references = 1; - to->authAlgorithm = from->authAlgorithm; - to->authKeyBits = from->authKeyBits; - to->keaType = from->keaType; - to->keaKeyBits = from->keaKeyBits; - - return to; - -loser: - if (to) { - if (version < SSL_LIBRARY_VERSION_3_0) { - if (to->u.ssl2.masterKey.data) - PORT_Free(to->u.ssl2.masterKey.data); - if (to->u.ssl2.cipherArg.data) - PORT_Free(to->u.ssl2.cipherArg.data); - } else { - SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE); - } - PORT_Free(to); - } - return NULL; -} - -/* -** Perform some mumbo jumbo on the ip-address and the session-id value to -** compute a hash value. -*/ -static PRUint32 -SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl) -{ - PRUint32 rv; - PRUint32 x[8]; - - memset(x, 0, sizeof x); - if (nl > sizeof x) - nl = sizeof x; - memcpy(x, s, nl); - - rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^ - addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^ - x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7]) % - cache->numSIDCacheSets; - return rv; -} - -/* -** Look something up in the cache. This will invalidate old entries -** in the process. Caller has locked the cache set! -** Returns PR_TRUE if found a valid match. PR_FALSE otherwise. -*/ -static sidCacheEntry * -FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now, - const PRIPv6Addr *addr, unsigned char *sessionID, - unsigned sessionIDLength) -{ - PRUint32 ndx = cache->sidCacheSets[setNum].next; - int i; - - sidCacheEntry *set = cache->sidCacheData + - (setNum * SID_CACHE_ENTRIES_PER_SET); - - for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) { - sidCacheEntry *sce; - - ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET; - sce = set + ndx; - - if (!sce->valid) - continue; - - if (now > sce->expirationTime) { - /* SessionID has timed out. Invalidate the entry. */ - SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x " - "time+=%x", - myPid, sce->addr.pr_s6_addr32[0], - sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2], - sce->addr.pr_s6_addr32[3], now, - sce->expirationTime)); - sce->valid = 0; - continue; - } - - /* - ** Next, examine specific session-id/addr data to see if the cache - ** entry matches our addr+session-id value - */ - if (sessionIDLength == sce->sessionIDLength && - !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) && - !memcmp(sce->sessionID, sessionID, sessionIDLength)) { - /* Found it */ - return sce; - } - } - - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return NULL; -} - -/************************************************************************/ - -/* This is the primary function for finding entries in the server's sid cache. - * Although it is static, this function is called via the global function - * pointer ssl_sid_lookup. - */ -static sslSessionID * -ServerSessionIDLookup(const PRIPv6Addr *addr, - unsigned char *sessionID, - unsigned int sessionIDLength, - CERTCertDBHandle *dbHandle) -{ - sslSessionID *sid = 0; - sidCacheEntry *psce; - certCacheEntry *pcce = 0; - srvNameCacheEntry *psnce = 0; - cacheDesc *cache = &globalCache; - PRUint32 now; - PRUint32 set; - PRInt32 cndx; - sidCacheEntry sce; - certCacheEntry cce; - srvNameCacheEntry snce; - - set = SIDindex(cache, addr, sessionID, sessionIDLength); - now = LockSet(cache, set, 0); - if (!now) - return NULL; - - psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength); - if (psce) { - if (psce->version >= SSL_LIBRARY_VERSION_3_0) { - if ((cndx = psce->u.ssl3.certIndex) != -1) { - - PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now); - if (gotLock) { - pcce = &cache->certCacheData[cndx]; - - /* See if the cert's session ID matches the sce cache. */ - if ((pcce->sessionIDLength == psce->sessionIDLength) && - !PORT_Memcmp(pcce->sessionID, psce->sessionID, - pcce->sessionIDLength)) { - cce = *pcce; - } else { - /* The cert doesen't match the SID cache entry, - ** so invalidate the SID cache entry. - */ - psce->valid = 0; - psce = 0; - pcce = 0; - } - UnlockSidCacheLock(cache->certCacheLock); - } else { - /* what the ??. Didn't get the cert cache lock. - ** Don't invalidate the SID cache entry, but don't find it. - */ - PORT_Assert(!("Didn't get cert Cache Lock!")); - psce = 0; - pcce = 0; - } - } - if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) { - PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock, - now); - if (gotLock) { - psnce = &cache->srvNameCacheData[cndx]; - - if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash, - SHA256_LENGTH)) { - snce = *psnce; - } else { - /* The name doesen't match the SID cache entry, - ** so invalidate the SID cache entry. - */ - psce->valid = 0; - psce = 0; - psnce = 0; - } - UnlockSidCacheLock(cache->srvNameCacheLock); - } else { - /* what the ??. Didn't get the cert cache lock. - ** Don't invalidate the SID cache entry, but don't find it. - */ - PORT_Assert(!("Didn't get name Cache Lock!")); - psce = 0; - psnce = 0; - } - } - } - if (psce) { - psce->lastAccessTime = now; - sce = *psce; /* grab a copy while holding the lock */ - } - } - UnlockSet(cache, set); - if (psce) { - /* sce conains a copy of the cache entry. - ** Convert shared memory format to local format - */ - sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle); - } - return sid; -} - -/* -** Place a sid into the cache, if it isn't already there. -*/ -static void -ServerSessionIDCache(sslSessionID *sid) -{ - sidCacheEntry sce; - PRUint32 now = 0; - PRUint16 version = sid->version; - cacheDesc *cache = &globalCache; - - if ((version >= SSL_LIBRARY_VERSION_3_0) && - (sid->u.ssl3.sessionIDLength == 0)) { - return; - } - - if (sid->cached == never_cached || sid->cached == invalid_cache) { - PRUint32 set; - - PORT_Assert(sid->creationTime != 0); - if (!sid->creationTime) - sid->lastAccessTime = sid->creationTime = ssl_Time(); - if (version < SSL_LIBRARY_VERSION_3_0) { - /* override caller's expiration time, which uses client timeout - * duration, not server timeout duration. - */ - sid->expirationTime = sid->creationTime + cache->ssl2Timeout; - SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " - "cipher=%d", - myPid, sid->cached, - sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], - sid->creationTime, sid->u.ssl2.cipherType)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, - SSL2_SESSIONID_BYTES)); - PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, - sid->u.ssl2.masterKey.len)); - PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, - sid->u.ssl2.cipherArg.len)); - } else { - /* override caller's expiration time, which uses client timeout - * duration, not server timeout duration. - */ - sid->expirationTime = sid->creationTime + cache->ssl3Timeout; - SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " - "cipherSuite=%d", - myPid, sid->cached, - sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], - sid->creationTime, sid->u.ssl3.cipherSuite)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength)); - } - - ConvertFromSID(&sce, sid); - - if (version >= SSL_LIBRARY_VERSION_3_0) { - SECItem *name = &sid->u.ssl3.srvName; - if (name->len && name->data) { - now = CacheSrvName(cache, name, &sce); - } - if (sid->peerCert != NULL) { - now = CacheCert(cache, sid->peerCert, &sce); - } - } - - set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength); - now = LockSet(cache, set, now); - if (now) { - PRUint32 next = cache->sidCacheSets[set].next; - PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next; - - /* Write out new cache entry */ - cache->sidCacheData[ndx] = sce; - - cache->sidCacheSets[set].next = - (next + 1) % SID_CACHE_ENTRIES_PER_SET; - - UnlockSet(cache, set); - sid->cached = in_server_cache; - } - } -} - -/* -** Although this is static, it is called from ssl via global function pointer -** ssl_sid_uncache. This invalidates the referenced cache entry. -*/ -static void -ServerSessionIDUncache(sslSessionID *sid) -{ - cacheDesc *cache = &globalCache; - PRUint8 *sessionID; - unsigned int sessionIDLength; - PRErrorCode err; - PRUint32 set; - PRUint32 now; - sidCacheEntry *psce; - - if (sid == NULL) - return; - - /* Uncaching a SID should never change the error code. - ** So save it here and restore it before exiting. - */ - err = PR_GetError(); - - if (sid->version < SSL_LIBRARY_VERSION_3_0) { - sessionID = sid->u.ssl2.sessionID; - sessionIDLength = SSL2_SESSIONID_BYTES; - SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x " - "cipher=%d", - myPid, sid->cached, - sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], - sid->creationTime, sid->u.ssl2.cipherType)); - PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); - PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, - sid->u.ssl2.masterKey.len)); - PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, - sid->u.ssl2.cipherArg.len)); - } else { - sessionID = sid->u.ssl3.sessionID; - sessionIDLength = sid->u.ssl3.sessionIDLength; - SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x " - "cipherSuite=%d", - myPid, sid->cached, - sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], - sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], - sid->creationTime, sid->u.ssl3.cipherSuite)); - PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); - } - set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength); - now = LockSet(cache, set, 0); - if (now) { - psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength); - if (psce) { - psce->valid = 0; - } - UnlockSet(cache, set); - } - sid->cached = invalid_cache; - PORT_SetError(err); -} - -#ifdef XP_OS2 - -#define INCL_DOSPROCESS -#include <os2.h> - -long -gettid(void) -{ - PTIB ptib; - PPIB ppib; - DosGetInfoBlocks(&ptib, &ppib); - return ((long)ptib->tib_ordinal); /* thread id */ -} -#endif - -static void -CloseCache(cacheDesc *cache) -{ - int locks_initialized = cache->numSIDCacheLocksInitialized; - - if (cache->cacheMem) { - if (cache->sharedCache) { - sidCacheLock *pLock = cache->sidCacheLocks; - for (; locks_initialized > 0; --locks_initialized, ++pLock) { - /* If everInherited is true, this shared cache was (and may - ** still be) in use by multiple processes. We do not wish to - ** destroy the mutexes while they are still in use, but we do - ** want to free mutex resources associated with this process. - */ - sslMutex_Destroy(&pLock->mutex, - cache->sharedCache->everInherited); - } - } - if (cache->shared) { - PR_MemUnmap(cache->cacheMem, cache->cacheMemSize); - } else { - PORT_Free(cache->cacheMem); - } - cache->cacheMem = NULL; - } - if (cache->cacheMemMap) { - PR_CloseFileMap(cache->cacheMemMap); - cache->cacheMemMap = NULL; - } - memset(cache, 0, sizeof *cache); -} - -static SECStatus -InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, - int maxSrvNameCacheEntries, PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, const char *directory, PRBool shared) -{ - ptrdiff_t ptr; - sidCacheLock *pLock; - char *cacheMem; - PRFileMap *cacheMemMap; - char *cfn = NULL; /* cache file name */ - int locks_initialized = 0; - int locks_to_initialize = 0; - PRUint32 init_time; - - if ((!cache) || (maxCacheEntries < 0) || (!directory)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (cache->cacheMem) { - /* Already done */ - return SECSuccess; - } - - /* make sure loser can clean up properly */ - cache->shared = shared; - cache->cacheMem = cacheMem = NULL; - cache->cacheMemMap = cacheMemMap = NULL; - cache->sharedCache = (cacheDesc *)0; - - cache->numSIDCacheLocksInitialized = 0; - cache->nextCertCacheEntry = 0; - cache->stopPolling = PR_FALSE; - cache->everInherited = PR_FALSE; - cache->poller = NULL; - cache->mutexTimeout = 0; - - cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries - : DEF_SID_CACHE_ENTRIES; - cache->numSIDCacheSets = - SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET); - - cache->numSIDCacheEntries = - cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET; - - cache->numSIDCacheLocks = - PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks); - - cache->numSIDCacheSetsPerLock = - SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks); - - cache->numCertCacheEntries = (maxCertCacheEntries > 0) ? maxCertCacheEntries - : 0; - cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ? maxSrvNameCacheEntries - : DEF_NAME_CACHE_ENTRIES; - - /* compute size of shared memory, and offsets of all pointers */ - ptr = 0; - cache->cacheMem = (char *)ptr; - ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT); - - cache->sidCacheLocks = (sidCacheLock *)ptr; - cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; - cache->certCacheLock = cache->keyCacheLock + 1; - cache->srvNameCacheLock = cache->certCacheLock + 1; - ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->sidCacheSets = (sidCacheSet *)ptr; - ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->sidCacheData = (sidCacheEntry *)ptr; - ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->certCacheData = (certCacheEntry *)ptr; - cache->sidCacheSize = - (char *)cache->certCacheData - (char *)cache->sidCacheData; - - if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) { - /* This is really a poor way to computer this! */ - cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry); - if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) - cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; - } - ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr; - cache->certCacheSize = - (char *)cache->keyCacheData - (char *)cache->certCacheData; - - cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS; - ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; - - cache->ticketKeyNameSuffix = (PRUint8 *)ptr; - ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix + - SESS_TICKET_KEY_VAR_NAME_LEN); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->ticketEncKey = (encKeyCacheEntry *)ptr; - ptr = (ptrdiff_t)(cache->ticketEncKey + 1); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->ticketMacKey = (encKeyCacheEntry *)ptr; - ptr = (ptrdiff_t)(cache->ticketMacKey + 1); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->ticketKeysValid = (PRUint32 *)ptr; - ptr = (ptrdiff_t)(cache->ticketKeysValid + 1); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->srvNameCacheData = (srvNameCacheEntry *)ptr; - cache->srvNameCacheSize = - cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry); - ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries); - ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); - - cache->cacheMemSize = ptr; - - if (ssl2_timeout) { - if (ssl2_timeout > MAX_SSL2_TIMEOUT) { - ssl2_timeout = MAX_SSL2_TIMEOUT; - } - if (ssl2_timeout < MIN_SSL2_TIMEOUT) { - ssl2_timeout = MIN_SSL2_TIMEOUT; - } - cache->ssl2Timeout = ssl2_timeout; - } else { - cache->ssl2Timeout = DEF_SSL2_TIMEOUT; - } - - if (ssl3_timeout) { - if (ssl3_timeout > MAX_SSL3_TIMEOUT) { - ssl3_timeout = MAX_SSL3_TIMEOUT; - } - if (ssl3_timeout < MIN_SSL3_TIMEOUT) { - ssl3_timeout = MIN_SSL3_TIMEOUT; - } - cache->ssl3Timeout = ssl3_timeout; - } else { - cache->ssl3Timeout = DEF_SSL3_TIMEOUT; - } - - if (shared) { - /* Create file names */ -#if defined(XP_UNIX) || defined(XP_BEOS) - /* there's some confusion here about whether PR_OpenAnonFileMap wants - ** a directory name or a file name for its first argument. - cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid); - */ - cfn = PR_smprintf("%s", directory); -#elif defined(XP_WIN32) - cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, - GetCurrentThreadId()); -#elif defined(XP_OS2) - cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, - gettid()); -#else -#error "Don't know how to create file name for this platform!" -#endif - if (!cfn) { - goto loser; - } - - /* Create cache */ - cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, - PR_PROT_READWRITE); - - PR_smprintf_free(cfn); - if (!cacheMemMap) { - goto loser; - } - - cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize); - } else { - cacheMem = PORT_Alloc(cache->cacheMemSize); - } - - if (!cacheMem) { - goto loser; - } - - /* Initialize shared memory. This may not be necessary on all platforms */ - memset(cacheMem, 0, cache->cacheMemSize); - - /* Copy cache descriptor header into shared memory */ - memcpy(cacheMem, cache, sizeof *cache); - - /* save private copies of these values */ - cache->cacheMemMap = cacheMemMap; - cache->cacheMem = cacheMem; - cache->sharedCache = (cacheDesc *)cacheMem; - - /* Fix pointers in our private copy of cache descriptor to point to - ** spaces in shared memory - */ - cache->sidCacheLocks = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->sidCacheLocks); - cache->keyCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->keyCacheLock); - cache->certCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->certCacheLock); - cache->srvNameCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheLock); - cache->sidCacheSets = (sidCacheSet *)(cache->cacheMem + (ptrdiff_t)cache->sidCacheSets); - cache->sidCacheData = (sidCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->sidCacheData); - cache->certCacheData = (certCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->certCacheData); - cache->keyCacheData = (SSLWrappedSymWrappingKey *)(cache->cacheMem + (ptrdiff_t)cache->keyCacheData); - cache->ticketKeyNameSuffix = (PRUint8 *)(cache->cacheMem + (ptrdiff_t)cache->ticketKeyNameSuffix); - cache->ticketEncKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->ticketEncKey); - cache->ticketMacKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->ticketMacKey); - cache->ticketKeysValid = (PRUint32 *)(cache->cacheMem + (ptrdiff_t)cache->ticketKeysValid); - cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData); - - /* initialize the locks */ - init_time = ssl_Time(); - pLock = cache->sidCacheLocks; - for (locks_to_initialize = cache->numSIDCacheLocks + 3; - locks_initialized < locks_to_initialize; - ++locks_initialized, ++pLock) { - - SECStatus err = sslMutex_Init(&pLock->mutex, shared); - if (err) { - cache->numSIDCacheLocksInitialized = locks_initialized; - goto loser; - } - pLock->timeStamp = init_time; - pLock->pid = 0; - } - cache->numSIDCacheLocksInitialized = locks_initialized; - - return SECSuccess; - -loser: - CloseCache(cache); - return SECFailure; -} - -PRUint32 -SSL_GetMaxServerCacheLocks(void) -{ - return ssl_max_sid_cache_locks + 2; - /* The extra two are the cert cache lock and the key cache lock. */ -} - -SECStatus -SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) -{ - /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock. - ** We'd like to test for a maximum value, but not all platforms' header - ** files provide a symbol or function or other means of determining - ** the maximum, other than trial and error. - */ - if (maxLocks < 3) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - ssl_max_sid_cache_locks = maxLocks - 2; - /* The extra two are the cert cache lock and the key cache lock. */ - return SECSuccess; -} - -static SECStatus -ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory, - PRBool shared, - int maxCacheEntries, - int maxCertCacheEntries, - int maxSrvNameCacheEntries) -{ - SECStatus rv; - - PORT_Assert(sizeof(sidCacheEntry) == 192); - PORT_Assert(sizeof(certCacheEntry) == 4096); - PORT_Assert(sizeof(srvNameCacheEntry) == 1072); - - rv = ssl_Init(); - if (rv != SECSuccess) { - return rv; - } - - myPid = SSL_GETPID(); - if (!directory) { - directory = DEFAULT_CACHE_DIRECTORY; - } - rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries, - maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout, - directory, shared); - if (rv) { - SET_ERROR_CODE - return SECFailure; - } - - ssl_sid_lookup = ServerSessionIDLookup; - ssl_sid_cache = ServerSessionIDCache; - ssl_sid_uncache = ServerSessionIDUncache; - return SECSuccess; -} - -SECStatus -SSL_ConfigServerSessionIDCacheInstance(cacheDesc *cache, - int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory, PRBool shared) -{ - return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, - ssl2_timeout, - ssl3_timeout, - directory, - shared, - maxCacheEntries, - -1, -1); -} - -SECStatus -SSL_ConfigServerSessionIDCache(int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory) -{ - ssl_InitSessionCacheLocks(); - return SSL_ConfigServerSessionIDCacheInstance(&globalCache, - maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE); -} - -SECStatus -SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache) -{ - CloseCache(cache); - return SECSuccess; -} - -SECStatus -SSL_ShutdownServerSessionIDCache(void) -{ -#if defined(XP_UNIX) || defined(XP_BEOS) - /* Stop the thread that polls cache for expired locks on Unix */ - StopLockPoller(&globalCache); -#endif - SSL3_ShutdownServerCache(); - return SSL_ShutdownServerSessionIDCacheInstance(&globalCache); -} - -/* Use this function, instead of SSL_ConfigServerSessionIDCache, - * if the cache will be shared by multiple processes. - */ -static SECStatus -ssl_ConfigMPServerSIDCacheWithOpt(PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory, - int maxCacheEntries, - int maxCertCacheEntries, - int maxSrvNameCacheEntries) -{ - char *envValue; - char *inhValue; - cacheDesc *cache = &globalCache; - PRUint32 fmStrLen; - SECStatus result; - PRStatus prStatus; - SECStatus putEnvFailed; - inheritance inherit; - char fmString[PR_FILEMAP_STRING_BUFSIZE]; - - isMultiProcess = PR_TRUE; - result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, - ssl2_timeout, ssl3_timeout, directory, PR_TRUE, - maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries); - if (result != SECSuccess) - return result; - - prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, - sizeof fmString, fmString); - if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) { - SET_ERROR_CODE - return SECFailure; - } - - inherit.cacheMemSize = cache->cacheMemSize; - inherit.fmStrLen = fmStrLen; - - inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit); - if (!inhValue || !strlen(inhValue)) { - SET_ERROR_CODE - return SECFailure; - } - envValue = PR_smprintf("%s,%s", inhValue, fmString); - if (!envValue || !strlen(envValue)) { - SET_ERROR_CODE - return SECFailure; - } - PORT_Free(inhValue); - - putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue); - PR_smprintf_free(envValue); - if (putEnvFailed) { - SET_ERROR_CODE - result = SECFailure; - } - -#if defined(XP_UNIX) || defined(XP_BEOS) - /* Launch thread to poll cache for expired locks on Unix */ - LaunchLockPoller(cache); -#endif - return result; -} - -/* Use this function, instead of SSL_ConfigServerSessionIDCache, - * if the cache will be shared by multiple processes. - */ -SECStatus -SSL_ConfigMPServerSIDCache(int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory) -{ - return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, - ssl3_timeout, - directory, - maxCacheEntries, - -1, -1); -} - -SECStatus -SSL_ConfigServerSessionIDCacheWithOpt( - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory, - int maxCacheEntries, - int maxCertCacheEntries, - int maxSrvNameCacheEntries, - PRBool enableMPCache) -{ - if (!enableMPCache) { - ssl_InitSessionCacheLocks(); - return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, - ssl2_timeout, ssl3_timeout, directory, PR_FALSE, - maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries); - } else { - return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout, - directory, maxCacheEntries, maxCertCacheEntries, - maxSrvNameCacheEntries); - } -} - -SECStatus -SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString) -{ - unsigned char *decoString = NULL; - char *fmString = NULL; - char *myEnvString = NULL; - unsigned int decoLen; - inheritance inherit; - cacheDesc my; -#ifdef WINNT - sidCacheLock *newLocks; - int locks_initialized = 0; - int locks_to_initialize = 0; -#endif - SECStatus status = ssl_Init(); - - if (status != SECSuccess) { - return status; - } - - myPid = SSL_GETPID(); - - /* If this child was created by fork(), and not by exec() on unix, - ** then isMultiProcess will already be set. - ** If not, we'll set it below. - */ - if (isMultiProcess) { - if (cache && cache->sharedCache) { - cache->sharedCache->everInherited = PR_TRUE; - } - return SECSuccess; /* already done. */ - } - - ssl_InitSessionCacheLocks(); - - ssl_sid_lookup = ServerSessionIDLookup; - ssl_sid_cache = ServerSessionIDCache; - ssl_sid_uncache = ServerSessionIDUncache; - - if (!envString) { - envString = PR_GetEnvSecure(envVarName); - if (!envString) { - SET_ERROR_CODE - return SECFailure; - } - } - myEnvString = PORT_Strdup(envString); - if (!myEnvString) - return SECFailure; - fmString = strchr(myEnvString, ','); - if (!fmString) - goto loser; - *fmString++ = 0; - - decoString = ATOB_AsciiToData(myEnvString, &decoLen); - if (!decoString) { - SET_ERROR_CODE - goto loser; - } - if (decoLen != sizeof inherit) { - SET_ERROR_CODE - goto loser; - } - - PORT_Memcpy(&inherit, decoString, sizeof inherit); - - if (strlen(fmString) != inherit.fmStrLen) { - goto loser; - } - - memset(cache, 0, sizeof *cache); - cache->cacheMemSize = inherit.cacheMemSize; - - /* Create cache */ - cache->cacheMemMap = PR_ImportFileMapFromString(fmString); - if (!cache->cacheMemMap) { - goto loser; - } - cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize); - if (!cache->cacheMem) { - goto loser; - } - cache->sharedCache = (cacheDesc *)cache->cacheMem; - - if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) { - SET_ERROR_CODE - goto loser; - } - - /* We're now going to overwrite the local cache instance with the - ** shared copy of the cache struct, then update several values in - ** the local cache using the values for cache->cacheMemMap and - ** cache->cacheMem computed just above. So, we copy cache into - ** the automatic variable "my", to preserve the variables while - ** cache is overwritten. - */ - my = *cache; /* save values computed above. */ - memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */ - - /* Fix pointers in our private copy of cache descriptor to point to - ** spaces in shared memory, whose address is now in "my". - */ - cache->sidCacheLocks = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->sidCacheLocks); - cache->keyCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->keyCacheLock); - cache->certCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->certCacheLock); - cache->srvNameCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->srvNameCacheLock); - cache->sidCacheSets = (sidCacheSet *)(my.cacheMem + (ptrdiff_t)cache->sidCacheSets); - cache->sidCacheData = (sidCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->sidCacheData); - cache->certCacheData = (certCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->certCacheData); - cache->keyCacheData = (SSLWrappedSymWrappingKey *)(my.cacheMem + (ptrdiff_t)cache->keyCacheData); - cache->ticketKeyNameSuffix = (PRUint8 *)(my.cacheMem + (ptrdiff_t)cache->ticketKeyNameSuffix); - cache->ticketEncKey = (encKeyCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->ticketEncKey); - cache->ticketMacKey = (encKeyCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->ticketMacKey); - cache->ticketKeysValid = (PRUint32 *)(my.cacheMem + (ptrdiff_t)cache->ticketKeysValid); - cache->srvNameCacheData = (srvNameCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->srvNameCacheData); - - cache->cacheMemMap = my.cacheMemMap; - cache->cacheMem = my.cacheMem; - cache->sharedCache = (cacheDesc *)cache->cacheMem; - -#ifdef WINNT - /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers - ** When NT fibers are used in a multi-process server, a second level of - ** locking is needed to prevent a deadlock, in case a fiber acquires the - ** cross-process mutex, yields, and another fiber is later scheduled on - ** the same native thread and tries to acquire the cross-process mutex. - ** We do this by using a PRLock in the sslMutex. However, it is stored in - ** shared memory as part of sidCacheLocks, and we don't want to overwrite - ** the PRLock of the parent process. So we need to make new, private - ** copies of sidCacheLocks before modifying the sslMutex with our own - ** PRLock - */ - - /* note from jpierre : this should be free'd in child processes when - ** a function is added to delete the SSL session cache in the future. - */ - locks_to_initialize = cache->numSIDCacheLocks + 3; - newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize); - if (!newLocks) - goto loser; - /* copy the old locks */ - memcpy(newLocks, cache->sidCacheLocks, - locks_to_initialize * sizeof(sidCacheLock)); - cache->sidCacheLocks = newLocks; - /* fix the locks */ - for (; locks_initialized < locks_to_initialize; ++locks_initialized) { - /* now, make a local PRLock in this sslMutex for this child process */ - SECStatus err; - err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex); - if (err != SECSuccess) { - cache->numSIDCacheLocksInitialized = locks_initialized; - goto loser; - } - } - cache->numSIDCacheLocksInitialized = locks_initialized; - - /* also fix the key and cert cache which use the last 2 lock entries */ - cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; - cache->certCacheLock = cache->keyCacheLock + 1; - cache->srvNameCacheLock = cache->certCacheLock + 1; -#endif - - PORT_Free(myEnvString); - PORT_Free(decoString); - - /* mark that we have inherited this. */ - cache->sharedCache->everInherited = PR_TRUE; - isMultiProcess = PR_TRUE; - - return SECSuccess; - -loser: - PORT_Free(myEnvString); - if (decoString) - PORT_Free(decoString); - CloseCache(cache); - return SECFailure; -} - -SECStatus -SSL_InheritMPServerSIDCache(const char *envString) -{ - return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString); -} - -#if defined(XP_UNIX) || defined(XP_BEOS) - -#define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */ - -static void -LockPoller(void *arg) -{ - cacheDesc *cache = (cacheDesc *)arg; - cacheDesc *sharedCache = cache->sharedCache; - sidCacheLock *pLock; - PRIntervalTime timeout; - PRUint32 now; - PRUint32 then; - int locks_polled = 0; - int locks_to_poll = cache->numSIDCacheLocks + 2; - PRUint32 expiration = cache->mutexTimeout; - - timeout = PR_SecondsToInterval(expiration); - while (!sharedCache->stopPolling) { - PR_Sleep(timeout); - if (sharedCache->stopPolling) - break; - - now = ssl_Time(); - then = now - expiration; - for (pLock = cache->sidCacheLocks, locks_polled = 0; - locks_to_poll > locks_polled && !sharedCache->stopPolling; - ++locks_polled, ++pLock) { - pid_t pid; - - if (pLock->timeStamp < then && - pLock->timeStamp != 0 && - (pid = pLock->pid) != 0) { - - /* maybe we should try the lock? */ - int result = kill(pid, 0); - if (result < 0 && errno == ESRCH) { - SECStatus rv; - /* No process exists by that pid any more. - ** Treat this mutex as abandoned. - */ - pLock->timeStamp = now; - pLock->pid = 0; - rv = sslMutex_Unlock(&pLock->mutex); - if (rv != SECSuccess) { - /* Now what? */ - } - } - } - } /* end of loop over locks */ - } /* end of entire polling loop */ -} - -/* Launch thread to poll cache for expired locks */ -static SECStatus -LaunchLockPoller(cacheDesc *cache) -{ - const char *timeoutString; - PRThread *pollerThread; - - cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT; - timeoutString = PR_GetEnvSecure("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT"); - if (timeoutString) { - long newTime = strtol(timeoutString, 0, 0); - if (newTime == 0) - return SECSuccess; /* application doesn't want poller thread */ - if (newTime > 0) - cache->mutexTimeout = (PRUint32)newTime; - /* if error (newTime < 0) ignore it and use default */ - } - - pollerThread = - PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); - if (!pollerThread) { - return SECFailure; - } - cache->poller = pollerThread; - return SECSuccess; -} - -/* Stop the thread that polls cache for expired locks */ -static SECStatus -StopLockPoller(cacheDesc *cache) -{ - if (!cache->poller) { - return SECSuccess; - } - cache->sharedCache->stopPolling = PR_TRUE; - if (PR_Interrupt(cache->poller) != PR_SUCCESS) { - return SECFailure; - } - if (PR_JoinThread(cache->poller) != PR_SUCCESS) { - return SECFailure; - } - cache->poller = NULL; - return SECSuccess; -} -#endif - -/************************************************************************ - * Code dealing with shared wrapped symmetric wrapping keys below * - ************************************************************************/ - -/* If now is zero, it implies that the lock is not held, and must be -** aquired here. -*/ -static PRBool -getSvrWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk, - cacheDesc *cache, - PRUint32 lockTime) -{ - PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; - SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx; - PRUint32 now = 0; - PRBool rv = PR_FALSE; - - if (!cache->cacheMem) { /* cache is uninitialized */ - PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); - return rv; - } - if (!lockTime) { - lockTime = now = LockSidCacheLock(cache->keyCacheLock, now); - if (!lockTime) { - return rv; - } - } - if (pwswk->exchKeyType == exchKeyType && - pwswk->symWrapMechIndex == symWrapMechIndex && - pwswk->wrappedSymKeyLen != 0) { - *wswk = *pwswk; - rv = PR_TRUE; - } - if (now) { - UnlockSidCacheLock(cache->keyCacheLock); - } - return rv; -} - -PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv; - - PORT_Assert((unsigned)exchKeyType < kt_kea_size); - PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)exchKeyType < kt_kea_size && - (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { - rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, - &globalCache, 0); - } else { - rv = PR_FALSE; - } - - return rv; -} - -/* Wrap and cache a session ticket key. */ -static PRBool -WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, - const char *keyName, encKeyCacheEntry *cacheEntry) -{ - SECItem wrappedKey = { siBuffer, NULL, 0 }; - - wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); - PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes)); - if (wrappedKey.len > sizeof(cacheEntry->bytes)) - return PR_FALSE; - wrappedKey.data = cacheEntry->bytes; - - if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) != - SECSuccess) { - SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.", - SSL_GETPID(), "unknown", keyName)); - return PR_FALSE; - } - cacheEntry->length = wrappedKey.len; - return PR_TRUE; -} - -static PRBool -GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) -{ - PK11SlotInfo *slot; - CK_MECHANISM_TYPE mechanismArray[2]; - PK11SymKey *aesKeyTmp = NULL; - PK11SymKey *macKeyTmp = NULL; - cacheDesc *cache = &globalCache; - PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; - PRUint8 *ticketKeyNameSuffix; - - if (!cache->cacheMem) { - /* cache is not initalized. Use stack buffer */ - ticketKeyNameSuffix = ticketKeyNameSuffixLocal; - } else { - ticketKeyNameSuffix = cache->ticketKeyNameSuffix; - } - - if (PK11_GenerateRandom(ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN) != - SECSuccess) { - SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.", - SSL_GETPID(), "unknown")); - goto loser; - } - - mechanismArray[0] = CKM_AES_CBC; - mechanismArray[1] = CKM_SHA256_HMAC; - - slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg); - if (slot) { - aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL, - AES_256_KEY_LENGTH, pwArg); - macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL, - SHA256_LENGTH, pwArg); - PK11_FreeSlot(slot); - } - - if (aesKeyTmp == NULL || macKeyTmp == NULL) { - SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.", - SSL_GETPID(), "unknown")); - goto loser; - } - PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN); - *aesKey = aesKeyTmp; - *macKey = macKeyTmp; - return PR_TRUE; - -loser: - if (aesKeyTmp) - PK11_FreeSymKey(aesKeyTmp); - if (macKeyTmp) - PK11_FreeSymKey(macKeyTmp); - return PR_FALSE; -} - -static PRBool -GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) -{ - PK11SymKey *aesKeyTmp = NULL; - PK11SymKey *macKeyTmp = NULL; - cacheDesc *cache = &globalCache; - - if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) { - goto loser; - } - - if (cache->cacheMem) { - /* Export the keys to the shared cache in wrapped form. */ - if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey)) - goto loser; - if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey)) - goto loser; - } - *aesKey = aesKeyTmp; - *macKey = macKeyTmp; - return PR_TRUE; - -loser: - if (aesKeyTmp) - PK11_FreeSymKey(aesKeyTmp); - if (macKeyTmp) - PK11_FreeSymKey(macKeyTmp); - return PR_FALSE; -} - -static PRBool -UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, - PK11SymKey **aesKey, PK11SymKey **macKey) -{ - SECItem wrappedKey = { siBuffer, NULL, 0 }; - PK11SymKey *aesKeyTmp = NULL; - PK11SymKey *macKeyTmp = NULL; - cacheDesc *cache = &globalCache; - - wrappedKey.data = cache->ticketEncKey->bytes; - wrappedKey.len = cache->ticketEncKey->length; - PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes)); - aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, - CKM_AES_CBC, CKA_DECRYPT, 0); - - wrappedKey.data = cache->ticketMacKey->bytes; - wrappedKey.len = cache->ticketMacKey->length; - PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes)); - macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, - CKM_SHA256_HMAC, CKA_SIGN, 0); - - if (aesKeyTmp == NULL || macKeyTmp == NULL) { - SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.", - SSL_GETPID(), "unknown")); - goto loser; - } - SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.", - SSL_GETPID(), "unknown")); - - PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN); - *aesKey = aesKeyTmp; - *macKey = macKeyTmp; - return PR_TRUE; - -loser: - if (aesKeyTmp) - PK11_FreeSymKey(aesKeyTmp); - if (macKeyTmp) - PK11_FreeSymKey(macKeyTmp); - return PR_FALSE; -} - -PRBool -ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, - SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) -{ - PRUint32 now = 0; - PRBool rv = PR_FALSE; - PRBool keysGenerated = PR_FALSE; - cacheDesc *cache = &globalCache; - - if (!cache->cacheMem) { - /* cache is uninitialized. Generate keys and return them - * without caching. */ - return GenerateTicketKeys(pwArg, keyName, aesKey, macKey); - } - - now = LockSidCacheLock(cache->keyCacheLock, now); - if (!now) - return rv; - - if (!*(cache->ticketKeysValid)) { - /* Keys do not exist, create them. */ - if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName, - aesKey, macKey)) - goto loser; - keysGenerated = PR_TRUE; - *(cache->ticketKeysValid) = 1; - } - - rv = PR_TRUE; - -loser: - UnlockSidCacheLock(cache->keyCacheLock); - if (rv && !keysGenerated) - rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey); - return rv; -} - -PRBool -ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey, - unsigned char *macKey) -{ - PRBool rv = PR_FALSE; - PRUint32 now = 0; - cacheDesc *cache = &globalCache; - PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH]; - PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; - PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix; - PRBool cacheIsEnabled = PR_TRUE; - - if (!cache->cacheMem) { /* cache is uninitialized */ - cacheIsEnabled = PR_FALSE; - ticketKeyNameSuffix = ticketKeyNameSuffixLocal; - ticketEncKeyPtr = ticketEncKey; - ticketMacKeyPtr = ticketMacKey; - } else { - /* these values have constant memory locations in the cache. - * Ok to reference them without holding the lock. */ - ticketKeyNameSuffix = cache->ticketKeyNameSuffix; - ticketEncKeyPtr = cache->ticketEncKey->bytes; - ticketMacKeyPtr = cache->ticketMacKey->bytes; - } - - if (cacheIsEnabled) { - /* Grab lock if initialized. */ - now = LockSidCacheLock(cache->keyCacheLock, now); - if (!now) - return rv; - } - /* Going to regenerate keys on every call if cache was not - * initialized. */ - if (!cacheIsEnabled || !*(cache->ticketKeysValid)) { - if (PK11_GenerateRandom(ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN) != - SECSuccess) - goto loser; - if (PK11_GenerateRandom(ticketEncKeyPtr, - AES_256_KEY_LENGTH) != SECSuccess) - goto loser; - if (PK11_GenerateRandom(ticketMacKeyPtr, - SHA256_LENGTH) != SECSuccess) - goto loser; - if (cacheIsEnabled) { - *(cache->ticketKeysValid) = 1; - } - } - - rv = PR_TRUE; - -loser: - if (cacheIsEnabled) { - UnlockSidCacheLock(cache->keyCacheLock); - } - if (rv) { - PORT_Memcpy(keyName, ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN); - PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH); - PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH); - } - return rv; -} - -/* The caller passes in the new value it wants - * to set. This code tests the wrapped sym key entry in the shared memory. - * If it is uninitialized, this function writes the caller's value into - * the disk entry, and returns false. - * Otherwise, it overwrites the caller's wswk with the value obtained from - * the disk, and returns PR_TRUE. - * This is all done while holding the locks/mutexes necessary to make - * the operation atomic. - */ -PRBool -ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) -{ - cacheDesc *cache = &globalCache; - PRBool rv = PR_FALSE; - SSL3KEAType exchKeyType = wswk->exchKeyType; - /* type of keys used to wrap SymWrapKey*/ - PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; - PRUint32 ndx; - PRUint32 now = 0; - SSLWrappedSymWrappingKey myWswk; - - if (!cache->cacheMem) { /* cache is uninitialized */ - PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); - return 0; - } - - PORT_Assert((unsigned)exchKeyType < kt_kea_size); - if ((unsigned)exchKeyType >= kt_kea_size) - return 0; - - PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) - return 0; - - ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; - PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */ - - now = LockSidCacheLock(cache->keyCacheLock, now); - if (now) { - rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, - &myWswk, cache, now); - if (rv) { - /* we found it on disk, copy it out to the caller. */ - PORT_Memcpy(wswk, &myWswk, sizeof *wswk); - } else { - /* Wasn't on disk, and we're still holding the lock, so write it. */ - cache->keyCacheData[ndx] = *wswk; - } - UnlockSidCacheLock(cache->keyCacheLock); - } - return rv; -} - -#else /* MAC version or other platform */ - -#include "seccomon.h" -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" - -SECStatus -SSL_ConfigServerSessionIDCache(int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory) -{ - PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)"); - return SECFailure; -} - -SECStatus -SSL_ConfigMPServerSIDCache(int maxCacheEntries, - PRUint32 ssl2_timeout, - PRUint32 ssl3_timeout, - const char *directory) -{ - PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)"); - return SECFailure; -} - -SECStatus -SSL_InheritMPServerSIDCache(const char *envString) -{ - PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)"); - return SECFailure; -} - -PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv = PR_FALSE; - PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)"); - return rv; -} - -/* This is a kind of test-and-set. The caller passes in the new value it wants - * to set. This code tests the wrapped sym key entry in the shared memory. - * If it is uninitialized, this function writes the caller's value into - * the disk entry, and returns false. - * Otherwise, it overwrites the caller's wswk with the value obtained from - * the disk, and returns PR_TRUE. - * This is all done while holding the locks/mutexes necessary to make - * the operation atomic. - */ -PRBool -ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv = PR_FALSE; - PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)"); - return rv; -} - -PRUint32 -SSL_GetMaxServerCacheLocks(void) -{ - PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)"); - return -1; -} - -SECStatus -SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) -{ - PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)"); - return SECFailure; -} - -#endif /* XP_UNIX || XP_WIN32 */
diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c deleted file mode 100644 index e82c916..0000000 --- a/net/third_party/nss/ssl/sslsock.c +++ /dev/null
@@ -1,3715 +0,0 @@ -/* - * vtables (and methods that call through them) for the 4 types of - * SSLSockets supported. Only one type is still supported. - * Various other functions. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "seccomon.h" -#include "cert.h" -#include "keyhi.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "nspr.h" -#include "private/pprio.h" -#ifndef NO_PKCS11_BYPASS -#include "blapi.h" -#endif -#include "nss.h" -#include "pk11pqg.h" - -#define SET_ERROR_CODE /* reminder */ - -static const sslSocketOps ssl_default_ops = { /* No SSL. */ - ssl_DefConnect, - NULL, - ssl_DefBind, - ssl_DefListen, - ssl_DefShutdown, - ssl_DefClose, - ssl_DefRecv, - ssl_DefSend, - ssl_DefRead, - ssl_DefWrite, - ssl_DefGetpeername, - ssl_DefGetsockname -}; - -static const sslSocketOps ssl_secure_ops = { /* SSL. */ - ssl_SecureConnect, - NULL, - ssl_DefBind, - ssl_DefListen, - ssl_SecureShutdown, - ssl_SecureClose, - ssl_SecureRecv, - ssl_SecureSend, - ssl_SecureRead, - ssl_SecureWrite, - ssl_DefGetpeername, - ssl_DefGetsockname -}; - -/* -** default settings for socket enables -*/ -static sslOptions ssl_defaults = { - { siBuffer, NULL, 0 }, /* nextProtoNego */ - PR_TRUE, /* useSecurity */ - PR_FALSE, /* useSocks */ - PR_FALSE, /* requestCertificate */ - 2, /* requireCertificate */ - PR_FALSE, /* handshakeAsClient */ - PR_FALSE, /* handshakeAsServer */ - PR_FALSE, - /* enableSSL2 */ /* now defaults to off in NSS 3.13 */ - PR_FALSE, /* unusedBit9 */ - PR_FALSE, /* unusedBit10 */ - PR_FALSE, /* noCache */ - PR_FALSE, /* fdx */ - PR_FALSE, - /* v2CompatibleHello */ /* now defaults to off in NSS 3.13 */ - PR_TRUE, /* detectRollBack */ - PR_FALSE, /* noStepDown */ - PR_FALSE, /* bypassPKCS11 */ - PR_FALSE, /* noLocks */ - PR_FALSE, /* enableSessionTickets */ - PR_FALSE, /* enableDeflate */ - 2, /* enableRenegotiation (default: requires extension) */ - PR_FALSE, /* requireSafeNegotiation */ - PR_FALSE, /* enableFalseStart */ - PR_TRUE, /* cbcRandomIV */ - PR_FALSE, /* enableOCSPStapling */ - PR_TRUE, /* enableNPN */ - PR_FALSE, /* enableALPN */ - PR_TRUE, /* reuseServerECDHEKey */ - PR_FALSE, /* enableFallbackSCSV */ - PR_TRUE, /* enableServerDhe */ - PR_FALSE, /* enableExtendedMS */ - PR_FALSE, /* enableSignedCertTimestamps */ -}; - -/* - * default range of enabled SSL/TLS protocols - */ -static SSLVersionRange versions_defaults_stream = { - SSL_LIBRARY_VERSION_TLS_1_0, - SSL_LIBRARY_VERSION_TLS_1_2 -}; - -static SSLVersionRange versions_defaults_datagram = { - SSL_LIBRARY_VERSION_TLS_1_1, - SSL_LIBRARY_VERSION_TLS_1_2 -}; - -#define VERSIONS_DEFAULTS(variant) \ - (variant == ssl_variant_stream ? &versions_defaults_stream : \ - &versions_defaults_datagram) -#define VERSIONS_POLICY_MIN(variant) \ - (variant == ssl_variant_stream ? NSS_TLS_VERSION_MIN_POLICY : \ - NSS_DTLS_VERSION_MIN_POLICY) -#define VERSIONS_POLICY_MAX(variant) \ - (variant == ssl_variant_stream ? NSS_TLS_VERSION_MAX_POLICY : \ - NSS_DTLS_VERSION_MAX_POLICY) - -sslSessionIDLookupFunc ssl_sid_lookup; -sslSessionIDCacheFunc ssl_sid_cache; -sslSessionIDUncacheFunc ssl_sid_uncache; - -static PRBool ssl_inited = PR_FALSE; -static PRDescIdentity ssl_layer_id; - -PRBool locksEverDisabled; /* implicitly PR_FALSE */ -PRBool ssl_force_locks; /* implicitly PR_FALSE */ -int ssl_lock_readers = 1; /* default true. */ -char ssl_debug; -char ssl_trace; -FILE *ssl_trace_iob; -FILE *ssl_keylog_iob; -char lockStatus[] = "Locks are ENABLED. "; -#define LOCKSTATUS_OFFSET 10 /* offset of ENABLED */ - -/* SRTP_NULL_HMAC_SHA1_80 and SRTP_NULL_HMAC_SHA1_32 are not implemented. */ -static const PRUint16 srtpCiphers[] = { - SRTP_AES128_CM_HMAC_SHA1_80, - SRTP_AES128_CM_HMAC_SHA1_32, - 0 -}; - -/* forward declarations. */ -static sslSocket *ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant variant); -static SECStatus ssl_MakeLocks(sslSocket *ss); -static void ssl_SetDefaultsFromEnvironment(void); -static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, - PRDescIdentity id); - -/************************************************************************/ - -/* -** Lookup a socket structure from a file descriptor. -** Only functions called through the PRIOMethods table should use this. -** Other app-callable functions should use ssl_FindSocket. -*/ -static sslSocket * -ssl_GetPrivate(PRFileDesc *fd) -{ - sslSocket *ss; - - PORT_Assert(fd != NULL); - PORT_Assert(fd->methods->file_type == PR_DESC_LAYERED); - PORT_Assert(fd->identity == ssl_layer_id); - - if (fd->methods->file_type != PR_DESC_LAYERED || - fd->identity != ssl_layer_id) { - PORT_SetError(PR_BAD_DESCRIPTOR_ERROR); - return NULL; - } - - ss = (sslSocket *)fd->secret; - /* Set ss->fd lazily. We can't rely on the value of ss->fd set by - * ssl_PushIOLayer because another PR_PushIOLayer call will switch the - * contents of the PRFileDesc pointed by ss->fd and the new layer. - * See bug 807250. - */ - ss->fd = fd; - return ss; -} - -/* This function tries to find the SSL layer in the stack. - * It searches for the first SSL layer at or below the argument fd, - * and failing that, it searches for the nearest SSL layer above the - * argument fd. It returns the private sslSocket from the found layer. - */ -sslSocket * -ssl_FindSocket(PRFileDesc *fd) -{ - PRFileDesc *layer; - sslSocket *ss; - - PORT_Assert(fd != NULL); - PORT_Assert(ssl_layer_id != 0); - - layer = PR_GetIdentitiesLayer(fd, ssl_layer_id); - if (layer == NULL) { - PORT_SetError(PR_BAD_DESCRIPTOR_ERROR); - return NULL; - } - - ss = (sslSocket *)layer->secret; - /* Set ss->fd lazily. We can't rely on the value of ss->fd set by - * ssl_PushIOLayer because another PR_PushIOLayer call will switch the - * contents of the PRFileDesc pointed by ss->fd and the new layer. - * See bug 807250. - */ - ss->fd = layer; - return ss; -} - -static sslSocket * -ssl_DupSocket(sslSocket *os) -{ - sslSocket *ss; - SECStatus rv; - - ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant); - if (ss) { - ss->opt = os->opt; - ss->opt.useSocks = PR_FALSE; - ss->vrange = os->vrange; - - ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID); - ss->url = !os->url ? NULL : PORT_Strdup(os->url); - - ss->ops = os->ops; - ss->rTimeout = os->rTimeout; - ss->wTimeout = os->wTimeout; - ss->cTimeout = os->cTimeout; - ss->dbHandle = os->dbHandle; - - /* copy ssl2&3 policy & prefs, even if it's not selected (yet) */ - ss->allowedByPolicy = os->allowedByPolicy; - ss->maybeAllowedByPolicy = os->maybeAllowedByPolicy; - ss->chosenPreference = os->chosenPreference; - PORT_Memcpy(ss->cipherSuites, os->cipherSuites, sizeof os->cipherSuites); - PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, os->ssl3.dtlsSRTPCiphers, - sizeof(PRUint16) * os->ssl3.dtlsSRTPCipherCount); - ss->ssl3.dtlsSRTPCipherCount = os->ssl3.dtlsSRTPCipherCount; - PORT_Memcpy(ss->ssl3.signatureAlgorithms, os->ssl3.signatureAlgorithms, - sizeof(ss->ssl3.signatureAlgorithms[0]) * - os->ssl3.signatureAlgorithmCount); - ss->ssl3.signatureAlgorithmCount = os->ssl3.signatureAlgorithmCount; - ss->ssl3.downgradeCheckVersion = os->ssl3.downgradeCheckVersion; - - ss->ssl3.dheWeakGroupEnabled = os->ssl3.dheWeakGroupEnabled; - ss->ssl3.numDHEGroups = os->ssl3.numDHEGroups; - if (os->ssl3.dheGroups) { - ss->ssl3.dheGroups = PORT_NewArray(SSLDHEGroupType, - os->ssl3.numDHEGroups); - if (!ss->ssl3.dheGroups) { - goto loser; - } - PORT_Memcpy(ss->ssl3.dheGroups, os->ssl3.dheGroups, - sizeof(SSLDHEGroupType) * os->ssl3.numDHEGroups); - } else { - ss->ssl3.dheGroups = NULL; - } - - if (os->cipherSpecs) { - ss->cipherSpecs = (unsigned char *)PORT_Alloc(os->sizeCipherSpecs); - if (ss->cipherSpecs) - PORT_Memcpy(ss->cipherSpecs, os->cipherSpecs, - os->sizeCipherSpecs); - ss->sizeCipherSpecs = os->sizeCipherSpecs; - ss->preferredCipher = os->preferredCipher; - } else { - ss->cipherSpecs = NULL; /* produced lazily */ - ss->sizeCipherSpecs = 0; - ss->preferredCipher = NULL; - } - if (ss->opt.useSecurity) { - /* This int should be SSLKEAType, but CC on Irix complains, - * during the for loop. - */ - int i; - sslServerCerts *oc = os->serverCerts; - sslServerCerts *sc = ss->serverCerts; - - for (i = kt_null; i < kt_kea_size; i++, oc++, sc++) { - if (oc->serverCert && oc->serverCertChain) { - sc->serverCert = CERT_DupCertificate(oc->serverCert); - sc->serverCertChain = CERT_DupCertList(oc->serverCertChain); - if (!sc->serverCertChain) - goto loser; - } else { - sc->serverCert = NULL; - sc->serverCertChain = NULL; - } - sc->serverKeyPair = oc->serverKeyPair ? ssl3_GetKeyPairRef(oc->serverKeyPair) - : NULL; - if (oc->serverKeyPair && !sc->serverKeyPair) - goto loser; - sc->serverKeyBits = oc->serverKeyBits; - ss->certStatusArray[i] = !os->certStatusArray[i] ? NULL : SECITEM_DupArray(NULL, os->certStatusArray[i]); - } - ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL : ssl3_GetKeyPairRef(os->stepDownKeyPair); - ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL : ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair); - ss->dheKeyPair = !os->dheKeyPair ? NULL : ssl3_GetKeyPairRef(os->dheKeyPair); - ss->dheParams = os->dheParams; - - /* - * XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL. - * XXX We should detect this, and not just march on with NULL pointers. - */ - ss->authCertificate = os->authCertificate; - ss->authCertificateArg = os->authCertificateArg; - ss->getClientAuthData = os->getClientAuthData; - ss->getClientAuthDataArg = os->getClientAuthDataArg; - ss->sniSocketConfig = os->sniSocketConfig; - ss->sniSocketConfigArg = os->sniSocketConfigArg; - ss->handleBadCert = os->handleBadCert; - ss->badCertArg = os->badCertArg; - ss->handshakeCallback = os->handshakeCallback; - ss->handshakeCallbackData = os->handshakeCallbackData; - ss->canFalseStartCallback = os->canFalseStartCallback; - ss->canFalseStartCallbackData = os->canFalseStartCallbackData; - ss->pkcs11PinArg = os->pkcs11PinArg; - ss->getChannelID = os->getChannelID; - ss->getChannelIDArg = os->getChannelIDArg; - - /* Create security data */ - rv = ssl_CopySecurityInfo(ss, os); - if (rv != SECSuccess) { - goto loser; - } - } - } - return ss; - -loser: - ssl_FreeSocket(ss); - return NULL; -} - -static void -ssl_DestroyLocks(sslSocket *ss) -{ - /* Destroy locks. */ - if (ss->firstHandshakeLock) { - PZ_DestroyMonitor(ss->firstHandshakeLock); - ss->firstHandshakeLock = NULL; - } - if (ss->ssl3HandshakeLock) { - PZ_DestroyMonitor(ss->ssl3HandshakeLock); - ss->ssl3HandshakeLock = NULL; - } - if (ss->specLock) { - NSSRWLock_Destroy(ss->specLock); - ss->specLock = NULL; - } - - if (ss->recvLock) { - PZ_DestroyLock(ss->recvLock); - ss->recvLock = NULL; - } - if (ss->sendLock) { - PZ_DestroyLock(ss->sendLock); - ss->sendLock = NULL; - } - if (ss->xmitBufLock) { - PZ_DestroyMonitor(ss->xmitBufLock); - ss->xmitBufLock = NULL; - } - if (ss->recvBufLock) { - PZ_DestroyMonitor(ss->recvBufLock); - ss->recvBufLock = NULL; - } -} - -/* Caller holds any relevant locks */ -static void -ssl_DestroySocketContents(sslSocket *ss) -{ - /* "i" should be of type SSLKEAType, but CC on IRIX complains during - * the for loop. - */ - int i; - - /* Free up socket */ - ssl_DestroySecurityInfo(&ss->sec); - - ssl3_DestroySSL3Info(ss); - - PORT_Free(ss->saveBuf.buf); - PORT_Free(ss->pendingBuf.buf); - ssl_DestroyGather(&ss->gs); - - if (ss->peerID != NULL) - PORT_Free(ss->peerID); - if (ss->url != NULL) - PORT_Free((void *)ss->url); /* CONST */ - if (ss->cipherSpecs) { - PORT_Free(ss->cipherSpecs); - ss->cipherSpecs = NULL; - ss->sizeCipherSpecs = 0; - } - - /* Clean up server configuration */ - for (i = kt_null; i < kt_kea_size; i++) { - sslServerCerts *sc = ss->serverCerts + i; - if (sc->serverCert != NULL) - CERT_DestroyCertificate(sc->serverCert); - if (sc->serverCertChain != NULL) - CERT_DestroyCertificateList(sc->serverCertChain); - if (sc->serverKeyPair != NULL) - ssl3_FreeKeyPair(sc->serverKeyPair); - if (ss->certStatusArray[i] != NULL) { - SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE); - ss->certStatusArray[i] = NULL; - } - if (ss->signedCertTimestamps[i].data) { - SECITEM_FreeItem(&ss->signedCertTimestamps[i], PR_FALSE); - } - } - if (ss->stepDownKeyPair) { - ssl3_FreeKeyPair(ss->stepDownKeyPair); - ss->stepDownKeyPair = NULL; - } - if (ss->ephemeralECDHKeyPair) { - ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); - ss->ephemeralECDHKeyPair = NULL; - } - if (ss->dheKeyPair) { - ssl3_FreeKeyPair(ss->dheKeyPair); - ss->dheKeyPair = NULL; - } - SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE); - if (ss->xtnData.sniNameArr) { - PORT_Free(ss->xtnData.sniNameArr); - ss->xtnData.sniNameArr = NULL; - } -} - -/* - * free an sslSocket struct, and all the stuff that hangs off of it - */ -void -ssl_FreeSocket(sslSocket *ss) -{ - /* Get every lock you can imagine! - ** Caller already holds these: - ** SSL_LOCK_READER(ss); - ** SSL_LOCK_WRITER(ss); - */ - ssl_Get1stHandshakeLock(ss); - ssl_GetRecvBufLock(ss); - ssl_GetSSL3HandshakeLock(ss); - ssl_GetXmitBufLock(ss); - ssl_GetSpecWriteLock(ss); - - ssl_DestroySocketContents(ss); - - /* Release all the locks acquired above. */ - SSL_UNLOCK_READER(ss); - SSL_UNLOCK_WRITER(ss); - ssl_Release1stHandshakeLock(ss); - ssl_ReleaseRecvBufLock(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_ReleaseXmitBufLock(ss); - ssl_ReleaseSpecWriteLock(ss); - - ssl_DestroyLocks(ss); - -#ifdef DEBUG - PORT_Memset(ss, 0x1f, sizeof *ss); -#endif - PORT_Free(ss); - return; -} - -/************************************************************************/ -SECStatus -ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled) -{ - PRFileDesc *osfd = ss->fd->lower; - SECStatus rv = SECFailure; - PRSocketOptionData opt; - - opt.option = PR_SockOpt_NoDelay; - opt.value.no_delay = (PRBool)!enabled; - - if (osfd->methods->setsocketoption) { - rv = (SECStatus)osfd->methods->setsocketoption(osfd, &opt); - } else { - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - } - - return rv; -} - -static void -ssl_ChooseOps(sslSocket *ss) -{ - ss->ops = ss->opt.useSecurity ? &ssl_secure_ops : &ssl_default_ops; -} - -/* Called from SSL_Enable (immediately below) */ -static SECStatus -PrepareSocket(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - - ssl_ChooseOps(ss); - return rv; -} - -SECStatus -SSL_Enable(PRFileDesc *fd, int which, PRBool on) -{ - return SSL_OptionSet(fd, which, on); -} - -#ifndef NO_PKCS11_BYPASS -static const PRCallOnceType pristineCallOnce; -static PRCallOnceType setupBypassOnce; - -static SECStatus -SSL_BypassShutdown(void *appData, void *nssData) -{ - /* unload freeBL shared library from memory */ - BL_Unload(); - setupBypassOnce = pristineCallOnce; - return SECSuccess; -} - -static PRStatus -SSL_BypassRegisterShutdown(void) -{ - SECStatus rv = NSS_RegisterShutdown(SSL_BypassShutdown, NULL); - PORT_Assert(SECSuccess == rv); - return SECSuccess == rv ? PR_SUCCESS : PR_FAILURE; -} -#endif - -static PRStatus -SSL_BypassSetup(void) -{ -#ifdef NO_PKCS11_BYPASS - /* Guarantee binary compatibility */ - return PR_SUCCESS; -#else - return PR_CallOnce(&setupBypassOnce, &SSL_BypassRegisterShutdown); -#endif -} - -static PRBool ssl_VersionIsSupportedByPolicy( - SSLProtocolVariant protocolVariant, SSL3ProtocolVersion version); - -/* Implements the semantics for SSL_OptionSet(SSL_ENABLE_TLS, on) described in - * ssl.h in the section "SSL version range setting API". - */ -static void -ssl_EnableTLS(SSLVersionRange *vrange, PRBool on) -{ - if (on) { - /* don't turn it on if tls1.0 disallowed by by policy */ - if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, - SSL_LIBRARY_VERSION_TLS_1_0)) { - return; - } - } - if (SSL3_ALL_VERSIONS_DISABLED(vrange)) { - if (on) { - vrange->min = SSL_LIBRARY_VERSION_TLS_1_0; - vrange->max = SSL_LIBRARY_VERSION_TLS_1_0; - } /* else don't change anything */ - return; - } - - if (on) { - /* Expand the range of enabled version to include TLS 1.0 */ - vrange->min = PR_MIN(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0); - vrange->max = PR_MAX(vrange->max, SSL_LIBRARY_VERSION_TLS_1_0); - } else { - /* Disable all TLS versions, leaving only SSL 3.0 if it was enabled */ - if (vrange->min == SSL_LIBRARY_VERSION_3_0) { - vrange->max = SSL_LIBRARY_VERSION_3_0; - } else { - /* Only TLS was enabled, so now no versions are. */ - vrange->min = SSL_LIBRARY_VERSION_NONE; - vrange->max = SSL_LIBRARY_VERSION_NONE; - } - } -} - -/* Implements the semantics for SSL_OptionSet(SSL_ENABLE_SSL3, on) described in - * ssl.h in the section "SSL version range setting API". - */ -static void -ssl_EnableSSL3(SSLVersionRange *vrange, PRBool on) -{ - if (on) { - /* don't turn it on if ssl3 disallowed by by policy */ - if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, - SSL_LIBRARY_VERSION_3_0)) { - return; - } - } - if (SSL3_ALL_VERSIONS_DISABLED(vrange)) { - if (on) { - vrange->min = SSL_LIBRARY_VERSION_3_0; - vrange->max = SSL_LIBRARY_VERSION_3_0; - } /* else don't change anything */ - return; - } - - if (on) { - /* Expand the range of enabled versions to include SSL 3.0. We know - * SSL 3.0 or some version of TLS is already enabled at this point, so - * we don't need to change vrange->max. - */ - vrange->min = SSL_LIBRARY_VERSION_3_0; - } else { - /* Disable SSL 3.0, leaving TLS unaffected. */ - if (vrange->max > SSL_LIBRARY_VERSION_3_0) { - vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0); - } else { - /* Only SSL 3.0 was enabled, so now no versions are. */ - vrange->min = SSL_LIBRARY_VERSION_NONE; - vrange->max = SSL_LIBRARY_VERSION_NONE; - } - } -} - -SECStatus -SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECSuccess; - PRBool holdingLocks; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd)); - return SECFailure; - } - - holdingLocks = (!ss->opt.noLocks); - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - switch (which) { - case SSL_SOCKS: - ss->opt.useSocks = PR_FALSE; - rv = PrepareSocket(ss); - if (on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } - break; - - case SSL_SECURITY: - ss->opt.useSecurity = on; - rv = PrepareSocket(ss); - break; - - case SSL_REQUEST_CERTIFICATE: - ss->opt.requestCertificate = on; - break; - - case SSL_REQUIRE_CERTIFICATE: - ss->opt.requireCertificate = on; - break; - - case SSL_HANDSHAKE_AS_CLIENT: - if (ss->opt.handshakeAsServer && on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - break; - } - ss->opt.handshakeAsClient = on; - break; - - case SSL_HANDSHAKE_AS_SERVER: - if (ss->opt.handshakeAsClient && on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - break; - } - ss->opt.handshakeAsServer = on; - break; - - case SSL_ENABLE_TLS: - if (IS_DTLS(ss)) { - if (on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; /* not allowed */ - } - break; - } - ssl_EnableTLS(&ss->vrange, on); - ss->preferredCipher = NULL; - if (ss->cipherSpecs) { - PORT_Free(ss->cipherSpecs); - ss->cipherSpecs = NULL; - ss->sizeCipherSpecs = 0; - } - break; - - case SSL_ENABLE_SSL3: - if (IS_DTLS(ss)) { - if (on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; /* not allowed */ - } - break; - } - ssl_EnableSSL3(&ss->vrange, on); - ss->preferredCipher = NULL; - if (ss->cipherSpecs) { - PORT_Free(ss->cipherSpecs); - ss->cipherSpecs = NULL; - ss->sizeCipherSpecs = 0; - } - break; - - case SSL_ENABLE_SSL2: - if (IS_DTLS(ss)) { - if (on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; /* not allowed */ - } - break; - } - if (on) { - /* don't turn it on if ssl2 disallowed by by policy */ - if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, - SSL_LIBRARY_VERSION_2)) { - break; - } - } - ss->opt.enableSSL2 = on; - if (on) { - ss->opt.v2CompatibleHello = on; - } - ss->preferredCipher = NULL; - if (ss->cipherSpecs) { - PORT_Free(ss->cipherSpecs); - ss->cipherSpecs = NULL; - ss->sizeCipherSpecs = 0; - } - break; - - case SSL_NO_CACHE: - ss->opt.noCache = on; - break; - - case SSL_ENABLE_FDX: - if (on && ss->opt.noLocks) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } - ss->opt.fdx = on; - break; - - case SSL_V2_COMPATIBLE_HELLO: - if (IS_DTLS(ss)) { - if (on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; /* not allowed */ - } - break; - } - ss->opt.v2CompatibleHello = on; - if (!on) { - ss->opt.enableSSL2 = on; - } - break; - - case SSL_ROLLBACK_DETECTION: - ss->opt.detectRollBack = on; - break; - - case SSL_NO_STEP_DOWN: - ss->opt.noStepDown = on; - if (on) - SSL_DisableExportCipherSuites(fd); - break; - - case SSL_BYPASS_PKCS11: - if (ss->handshakeBegun) { - PORT_SetError(PR_INVALID_STATE_ERROR); - rv = SECFailure; - } else { - if (PR_FALSE != on) { - if (PR_SUCCESS == SSL_BypassSetup()) { -#ifdef NO_PKCS11_BYPASS - ss->opt.bypassPKCS11 = PR_FALSE; -#else - ss->opt.bypassPKCS11 = on; -#endif - } else { - rv = SECFailure; - } - } else { - ss->opt.bypassPKCS11 = PR_FALSE; - } - } - break; - - case SSL_NO_LOCKS: - if (on && ss->opt.fdx) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } - if (on && ssl_force_locks) - on = PR_FALSE; /* silent override */ - ss->opt.noLocks = on; - if (on) { - locksEverDisabled = PR_TRUE; - strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED."); - } else if (!holdingLocks) { - rv = ssl_MakeLocks(ss); - if (rv != SECSuccess) { - ss->opt.noLocks = PR_TRUE; - } - } - break; - - case SSL_ENABLE_SESSION_TICKETS: - ss->opt.enableSessionTickets = on; - break; - - case SSL_ENABLE_DEFLATE: - ss->opt.enableDeflate = on; - break; - - case SSL_ENABLE_RENEGOTIATION: - ss->opt.enableRenegotiation = on; - break; - - case SSL_REQUIRE_SAFE_NEGOTIATION: - ss->opt.requireSafeNegotiation = on; - break; - - case SSL_ENABLE_FALSE_START: - ss->opt.enableFalseStart = on; - break; - - case SSL_CBC_RANDOM_IV: - ss->opt.cbcRandomIV = on; - break; - - case SSL_ENABLE_OCSP_STAPLING: - ss->opt.enableOCSPStapling = on; - break; - - case SSL_ENABLE_NPN: - ss->opt.enableNPN = on; - break; - - case SSL_ENABLE_ALPN: - ss->opt.enableALPN = on; - break; - - case SSL_REUSE_SERVER_ECDHE_KEY: - ss->opt.reuseServerECDHEKey = on; - break; - - case SSL_ENABLE_FALLBACK_SCSV: - ss->opt.enableFallbackSCSV = on; - break; - - case SSL_ENABLE_SERVER_DHE: - ss->opt.enableServerDhe = on; - break; - - case SSL_ENABLE_EXTENDED_MASTER_SECRET: - ss->opt.enableExtendedMS = on; - break; - - case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - ss->opt.enableSignedCertTimestamps = on; - break; - - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } - - /* We can't use the macros for releasing the locks here, - * because ss->opt.noLocks might have changed just above. - * We must release these locks (monitors) here, if we aquired them above, - * regardless of the current value of ss->opt.noLocks. - */ - if (holdingLocks) { - PZ_ExitMonitor((ss)->ssl3HandshakeLock); - PZ_ExitMonitor((ss)->firstHandshakeLock); - } - - return rv; -} - -SECStatus -SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECSuccess; - PRBool on = PR_FALSE; - - if (!pOn) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd)); - *pOn = PR_FALSE; - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - switch (which) { - case SSL_SOCKS: - on = PR_FALSE; - break; - case SSL_SECURITY: - on = ss->opt.useSecurity; - break; - case SSL_REQUEST_CERTIFICATE: - on = ss->opt.requestCertificate; - break; - case SSL_REQUIRE_CERTIFICATE: - on = ss->opt.requireCertificate; - break; - case SSL_HANDSHAKE_AS_CLIENT: - on = ss->opt.handshakeAsClient; - break; - case SSL_HANDSHAKE_AS_SERVER: - on = ss->opt.handshakeAsServer; - break; - case SSL_ENABLE_TLS: - on = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0; - break; - case SSL_ENABLE_SSL3: - on = ss->vrange.min == SSL_LIBRARY_VERSION_3_0; - break; - case SSL_ENABLE_SSL2: - on = ss->opt.enableSSL2; - break; - case SSL_NO_CACHE: - on = ss->opt.noCache; - break; - case SSL_ENABLE_FDX: - on = ss->opt.fdx; - break; - case SSL_V2_COMPATIBLE_HELLO: - on = ss->opt.v2CompatibleHello; - break; - case SSL_ROLLBACK_DETECTION: - on = ss->opt.detectRollBack; - break; - case SSL_NO_STEP_DOWN: - on = ss->opt.noStepDown; - break; - case SSL_BYPASS_PKCS11: - on = ss->opt.bypassPKCS11; - break; - case SSL_NO_LOCKS: - on = ss->opt.noLocks; - break; - case SSL_ENABLE_SESSION_TICKETS: - on = ss->opt.enableSessionTickets; - break; - case SSL_ENABLE_DEFLATE: - on = ss->opt.enableDeflate; - break; - case SSL_ENABLE_RENEGOTIATION: - on = ss->opt.enableRenegotiation; - break; - case SSL_REQUIRE_SAFE_NEGOTIATION: - on = ss->opt.requireSafeNegotiation; - break; - case SSL_ENABLE_FALSE_START: - on = ss->opt.enableFalseStart; - break; - case SSL_CBC_RANDOM_IV: - on = ss->opt.cbcRandomIV; - break; - case SSL_ENABLE_OCSP_STAPLING: - on = ss->opt.enableOCSPStapling; - break; - case SSL_ENABLE_NPN: - on = ss->opt.enableNPN; - break; - case SSL_ENABLE_ALPN: - on = ss->opt.enableALPN; - break; - case SSL_REUSE_SERVER_ECDHE_KEY: - on = ss->opt.reuseServerECDHEKey; - break; - case SSL_ENABLE_FALLBACK_SCSV: - on = ss->opt.enableFallbackSCSV; - break; - case SSL_ENABLE_SERVER_DHE: - on = ss->opt.enableServerDhe; - break; - case SSL_ENABLE_EXTENDED_MASTER_SECRET: - on = ss->opt.enableExtendedMS; - break; - case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - on = ss->opt.enableSignedCertTimestamps; - break; - - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - *pOn = on; - return rv; -} - -SECStatus -SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) -{ - SECStatus rv = SECSuccess; - PRBool on = PR_FALSE; - - if (!pOn) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ssl_SetDefaultsFromEnvironment(); - - switch (which) { - case SSL_SOCKS: - on = PR_FALSE; - break; - case SSL_SECURITY: - on = ssl_defaults.useSecurity; - break; - case SSL_REQUEST_CERTIFICATE: - on = ssl_defaults.requestCertificate; - break; - case SSL_REQUIRE_CERTIFICATE: - on = ssl_defaults.requireCertificate; - break; - case SSL_HANDSHAKE_AS_CLIENT: - on = ssl_defaults.handshakeAsClient; - break; - case SSL_HANDSHAKE_AS_SERVER: - on = ssl_defaults.handshakeAsServer; - break; - case SSL_ENABLE_TLS: - on = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0; - break; - case SSL_ENABLE_SSL3: - on = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0; - break; - case SSL_ENABLE_SSL2: - on = ssl_defaults.enableSSL2; - break; - case SSL_NO_CACHE: - on = ssl_defaults.noCache; - break; - case SSL_ENABLE_FDX: - on = ssl_defaults.fdx; - break; - case SSL_V2_COMPATIBLE_HELLO: - on = ssl_defaults.v2CompatibleHello; - break; - case SSL_ROLLBACK_DETECTION: - on = ssl_defaults.detectRollBack; - break; - case SSL_NO_STEP_DOWN: - on = ssl_defaults.noStepDown; - break; - case SSL_BYPASS_PKCS11: - on = ssl_defaults.bypassPKCS11; - break; - case SSL_NO_LOCKS: - on = ssl_defaults.noLocks; - break; - case SSL_ENABLE_SESSION_TICKETS: - on = ssl_defaults.enableSessionTickets; - break; - case SSL_ENABLE_DEFLATE: - on = ssl_defaults.enableDeflate; - break; - case SSL_ENABLE_RENEGOTIATION: - on = ssl_defaults.enableRenegotiation; - break; - case SSL_REQUIRE_SAFE_NEGOTIATION: - on = ssl_defaults.requireSafeNegotiation; - break; - case SSL_ENABLE_FALSE_START: - on = ssl_defaults.enableFalseStart; - break; - case SSL_CBC_RANDOM_IV: - on = ssl_defaults.cbcRandomIV; - break; - case SSL_ENABLE_OCSP_STAPLING: - on = ssl_defaults.enableOCSPStapling; - break; - case SSL_ENABLE_NPN: - on = ssl_defaults.enableNPN; - break; - case SSL_ENABLE_ALPN: - on = ssl_defaults.enableALPN; - break; - case SSL_REUSE_SERVER_ECDHE_KEY: - on = ssl_defaults.reuseServerECDHEKey; - break; - case SSL_ENABLE_FALLBACK_SCSV: - on = ssl_defaults.enableFallbackSCSV; - break; - case SSL_ENABLE_SERVER_DHE: - on = ssl_defaults.enableServerDhe; - break; - case SSL_ENABLE_EXTENDED_MASTER_SECRET: - on = ssl_defaults.enableExtendedMS; - break; - case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - on = ssl_defaults.enableSignedCertTimestamps; - break; - - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } - - *pOn = on; - return rv; -} - -/* XXX Use Global Lock to protect this stuff. */ -SECStatus -SSL_EnableDefault(int which, PRBool on) -{ - return SSL_OptionSetDefault(which, on); -} - -SECStatus -SSL_OptionSetDefault(PRInt32 which, PRBool on) -{ - SECStatus status = ssl_Init(); - - if (status != SECSuccess) { - return status; - } - - ssl_SetDefaultsFromEnvironment(); - - switch (which) { - case SSL_SOCKS: - ssl_defaults.useSocks = PR_FALSE; - if (on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - break; - - case SSL_SECURITY: - ssl_defaults.useSecurity = on; - break; - - case SSL_REQUEST_CERTIFICATE: - ssl_defaults.requestCertificate = on; - break; - - case SSL_REQUIRE_CERTIFICATE: - ssl_defaults.requireCertificate = on; - break; - - case SSL_HANDSHAKE_AS_CLIENT: - if (ssl_defaults.handshakeAsServer && on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - ssl_defaults.handshakeAsClient = on; - break; - - case SSL_HANDSHAKE_AS_SERVER: - if (ssl_defaults.handshakeAsClient && on) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - ssl_defaults.handshakeAsServer = on; - break; - - case SSL_ENABLE_TLS: - ssl_EnableTLS(&versions_defaults_stream, on); - break; - - case SSL_ENABLE_SSL3: - ssl_EnableSSL3(&versions_defaults_stream, on); - break; - - case SSL_ENABLE_SSL2: - if (on) { - /* don't turn it on if ssl2 disallowed by by policy */ - if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, - SSL_LIBRARY_VERSION_2)) { - break; - } - } - ssl_defaults.enableSSL2 = on; - if (on) { - ssl_defaults.v2CompatibleHello = on; - } - break; - - case SSL_NO_CACHE: - ssl_defaults.noCache = on; - break; - - case SSL_ENABLE_FDX: - if (on && ssl_defaults.noLocks) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - ssl_defaults.fdx = on; - break; - - case SSL_V2_COMPATIBLE_HELLO: - ssl_defaults.v2CompatibleHello = on; - if (!on) { - ssl_defaults.enableSSL2 = on; - } - break; - - case SSL_ROLLBACK_DETECTION: - ssl_defaults.detectRollBack = on; - break; - - case SSL_NO_STEP_DOWN: - ssl_defaults.noStepDown = on; - if (on) - SSL_DisableDefaultExportCipherSuites(); - break; - - case SSL_BYPASS_PKCS11: - if (PR_FALSE != on) { - if (PR_SUCCESS == SSL_BypassSetup()) { -#ifdef NO_PKCS11_BYPASS - ssl_defaults.bypassPKCS11 = PR_FALSE; -#else - ssl_defaults.bypassPKCS11 = on; -#endif - } else { - return SECFailure; - } - } else { - ssl_defaults.bypassPKCS11 = PR_FALSE; - } - break; - - case SSL_NO_LOCKS: - if (on && ssl_defaults.fdx) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (on && ssl_force_locks) - on = PR_FALSE; /* silent override */ - ssl_defaults.noLocks = on; - if (on) { - locksEverDisabled = PR_TRUE; - strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED."); - } - break; - - case SSL_ENABLE_SESSION_TICKETS: - ssl_defaults.enableSessionTickets = on; - break; - - case SSL_ENABLE_DEFLATE: - ssl_defaults.enableDeflate = on; - break; - - case SSL_ENABLE_RENEGOTIATION: - ssl_defaults.enableRenegotiation = on; - break; - - case SSL_REQUIRE_SAFE_NEGOTIATION: - ssl_defaults.requireSafeNegotiation = on; - break; - - case SSL_ENABLE_FALSE_START: - ssl_defaults.enableFalseStart = on; - break; - - case SSL_CBC_RANDOM_IV: - ssl_defaults.cbcRandomIV = on; - break; - - case SSL_ENABLE_OCSP_STAPLING: - ssl_defaults.enableOCSPStapling = on; - break; - - case SSL_ENABLE_NPN: - ssl_defaults.enableNPN = on; - break; - - case SSL_ENABLE_ALPN: - ssl_defaults.enableALPN = on; - break; - - case SSL_REUSE_SERVER_ECDHE_KEY: - ssl_defaults.reuseServerECDHEKey = on; - break; - - case SSL_ENABLE_FALLBACK_SCSV: - ssl_defaults.enableFallbackSCSV = on; - break; - - case SSL_ENABLE_SERVER_DHE: - ssl_defaults.enableServerDhe = on; - break; - - case SSL_ENABLE_EXTENDED_MASTER_SECRET: - ssl_defaults.enableExtendedMS = on; - break; - - case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - ssl_defaults.enableSignedCertTimestamps = on; - break; - - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - return SECSuccess; -} - -/* function tells us if the cipher suite is one that we no longer support. */ -static PRBool -ssl_IsRemovedCipherSuite(PRInt32 suite) -{ - switch (suite) { - case SSL_FORTEZZA_DMS_WITH_NULL_SHA: - case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: - case SSL_FORTEZZA_DMS_WITH_RC4_128_SHA: - return PR_TRUE; - default: - return PR_FALSE; - } -} - -/* Part of the public NSS API. - * Since this is a global (not per-socket) setting, we cannot use the - * HandshakeLock to protect this. Probably want a global lock. - */ -SECStatus -SSL_SetPolicy(long which, int policy) -{ - if ((which & 0xfffe) == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) { - /* one of the two old FIPS ciphers */ - if (which == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) - which = SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA; - else if (which == SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA) - which = SSL_RSA_FIPS_WITH_DES_CBC_SHA; - } - if (ssl_IsRemovedCipherSuite(which)) - return SECSuccess; - return SSL_CipherPolicySet(which, policy); -} - -SECStatus -ssl_CipherPolicySet(PRInt32 which, PRInt32 policy) -{ - SECStatus rv = SECSuccess; - - if (ssl_IsRemovedCipherSuite(which)) { - rv = SECSuccess; - } else if (SSL_IS_SSL2_CIPHER(which)) { - rv = ssl2_SetPolicy(which, policy); - } else { - rv = ssl3_SetPolicy((ssl3CipherSuite)which, policy); - } - return rv; -} -SECStatus -SSL_CipherPolicySet(PRInt32 which, PRInt32 policy) -{ - SECStatus rv = ssl_Init(); - - if (rv != SECSuccess) { - return rv; - } - return ssl_CipherPolicySet(which, policy); -} - -SECStatus -SSL_CipherPolicyGet(PRInt32 which, PRInt32 *oPolicy) -{ - SECStatus rv; - - if (!oPolicy) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (ssl_IsRemovedCipherSuite(which)) { - *oPolicy = SSL_NOT_ALLOWED; - rv = SECSuccess; - } else if (SSL_IS_SSL2_CIPHER(which)) { - rv = ssl2_GetPolicy(which, oPolicy); - } else { - rv = ssl3_GetPolicy((ssl3CipherSuite)which, oPolicy); - } - return rv; -} - -/* Part of the public NSS API. - * Since this is a global (not per-socket) setting, we cannot use the - * HandshakeLock to protect this. Probably want a global lock. - * These changes have no effect on any sslSockets already created. - */ -SECStatus -SSL_EnableCipher(long which, PRBool enabled) -{ - if ((which & 0xfffe) == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) { - /* one of the two old FIPS ciphers */ - if (which == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) - which = SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA; - else if (which == SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA) - which = SSL_RSA_FIPS_WITH_DES_CBC_SHA; - } - if (ssl_IsRemovedCipherSuite(which)) - return SECSuccess; - return SSL_CipherPrefSetDefault(which, enabled); -} - -SECStatus -ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled) -{ - SECStatus rv = SECSuccess; - - if (ssl_IsRemovedCipherSuite(which)) - return SECSuccess; - if (enabled && ssl_defaults.noStepDown && SSL_IsExportCipherSuite(which)) { - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); - return SECFailure; - } - if (SSL_IS_SSL2_CIPHER(which)) { - rv = ssl2_CipherPrefSetDefault(which, enabled); - } else { - rv = ssl3_CipherPrefSetDefault((ssl3CipherSuite)which, enabled); - } - return rv; -} - -SECStatus -SSL_CipherPrefSetDefault(PRInt32 which, PRBool enabled) -{ - SECStatus rv = ssl_Init(); - - if (rv != SECSuccess) { - return rv; - } - return ssl_CipherPrefSetDefault(which, enabled); -} - -SECStatus -SSL_CipherPrefGetDefault(PRInt32 which, PRBool *enabled) -{ - SECStatus rv; - - if (!enabled) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (ssl_IsRemovedCipherSuite(which)) { - *enabled = PR_FALSE; - rv = SECSuccess; - } else if (SSL_IS_SSL2_CIPHER(which)) { - rv = ssl2_CipherPrefGetDefault(which, enabled); - } else { - rv = ssl3_CipherPrefGetDefault((ssl3CipherSuite)which, enabled); - } - return rv; -} - -SECStatus -SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled) -{ - SECStatus rv; - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd)); - return SECFailure; - } - if (ssl_IsRemovedCipherSuite(which)) - return SECSuccess; - if (enabled && ss->opt.noStepDown && SSL_IsExportCipherSuite(which)) { - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); - return SECFailure; - } - if (SSL_IS_SSL2_CIPHER(which)) { - rv = ssl2_CipherPrefSet(ss, which, enabled); - } else { - rv = ssl3_CipherPrefSet(ss, (ssl3CipherSuite)which, enabled); - } - return rv; -} - -SECStatus -SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, unsigned int len) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in CipherOrderSet", SSL_GETPID(), - fd)); - return SECFailure; - } - return ssl3_CipherOrderSet(ss, ciphers, len); -} - -SECStatus -SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled) -{ - SECStatus rv; - sslSocket *ss = ssl_FindSocket(fd); - - if (!enabled) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefGet", SSL_GETPID(), fd)); - *enabled = PR_FALSE; - return SECFailure; - } - if (ssl_IsRemovedCipherSuite(which)) { - *enabled = PR_FALSE; - rv = SECSuccess; - } else if (SSL_IS_SSL2_CIPHER(which)) { - rv = ssl2_CipherPrefGet(ss, which, enabled); - } else { - rv = ssl3_CipherPrefGet(ss, (ssl3CipherSuite)which, enabled); - } - return rv; -} - -SECStatus -NSS_SetDomesticPolicy(void) -{ - SECStatus status = SECSuccess; - const PRUint16 *cipher; - SECStatus rv; - PRUint32 policy; - - /* If we've already defined some policy oids, skip changing them */ - rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy); - if ((rv == SECSuccess) && (policy & NSS_USE_POLICY_IN_SSL)) { - return ssl_Init(); /* make sure the policies have bee loaded */ - } - - for (cipher = SSL_ImplementedCiphers; *cipher != 0; ++cipher) { - status = SSL_SetPolicy(*cipher, SSL_ALLOWED); - if (status != SECSuccess) - break; - } - return status; -} - -SECStatus -NSS_SetExportPolicy(void) -{ - return NSS_SetDomesticPolicy(); -} - -SECStatus -NSS_SetFrancePolicy(void) -{ - return NSS_SetDomesticPolicy(); -} - -SECStatus -SSL_DHEGroupPrefSet(PRFileDesc *fd, - SSLDHEGroupType *groups, - PRUint16 num_groups) -{ - sslSocket *ss; - - if ((num_groups && !groups) || (!num_groups && groups)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DHEGroupPrefSet", SSL_GETPID(), fd)); - return SECFailure; - } - - if (ss->ssl3.dheGroups) { - PORT_Free(ss->ssl3.dheGroups); - ss->ssl3.dheGroups = NULL; - ss->ssl3.numDHEGroups = 0; - } - - if (groups) { - ss->ssl3.dheGroups = PORT_NewArray(SSLDHEGroupType, num_groups); - if (!ss->ssl3.dheGroups) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - PORT_Memcpy(ss->ssl3.dheGroups, groups, - sizeof(SSLDHEGroupType) * num_groups); - } - return SECSuccess; -} - -PRCallOnceType gWeakDHParamsRegisterOnce; -int gWeakDHParamsRegisterError; - -PRCallOnceType gWeakDHParamsOnce; -int gWeakDHParamsError; -/* As our code allocates type PQGParams, we'll keep it around, - * even though we only make use of it's parameters through gWeakDHParam. */ -static PQGParams *gWeakParamsPQG; -static ssl3DHParams *gWeakDHParams; - -static PRStatus -ssl3_CreateWeakDHParams(void) -{ - PQGVerify *vfy; - SECStatus rv, passed; - - PORT_Assert(!gWeakDHParams && !gWeakParamsPQG); - - rv = PK11_PQG_ParamGenV2(1024, 160, 64 /*maximum seed that will work*/, - &gWeakParamsPQG, &vfy); - if (rv != SECSuccess) { - gWeakDHParamsError = PORT_GetError(); - return PR_FAILURE; - } - - rv = PK11_PQG_VerifyParams(gWeakParamsPQG, vfy, &passed); - if (rv != SECSuccess || passed != SECSuccess) { - SSL_DBG(("%d: PK11_PQG_VerifyParams failed in ssl3_CreateWeakDHParams", - SSL_GETPID())); - gWeakDHParamsError = PORT_GetError(); - return PR_FAILURE; - } - - gWeakDHParams = PORT_ArenaNew(gWeakParamsPQG->arena, ssl3DHParams); - if (!gWeakDHParams) { - gWeakDHParamsError = PORT_GetError(); - return PR_FAILURE; - } - - gWeakDHParams->prime.data = gWeakParamsPQG->prime.data; - gWeakDHParams->prime.len = gWeakParamsPQG->prime.len; - gWeakDHParams->base.data = gWeakParamsPQG->base.data; - gWeakDHParams->base.len = gWeakParamsPQG->base.len; - - PK11_PQG_DestroyVerify(vfy); - return PR_SUCCESS; -} - -static SECStatus -ssl3_WeakDHParamsShutdown(void *appData, void *nssData) -{ - if (gWeakParamsPQG) { - PK11_PQG_DestroyParams(gWeakParamsPQG); - gWeakParamsPQG = NULL; - gWeakDHParams = NULL; - } - return SECSuccess; -} - -static PRStatus -ssl3_WeakDHParamsRegisterShutdown(void) -{ - SECStatus rv; - rv = NSS_RegisterShutdown(ssl3_WeakDHParamsShutdown, NULL); - if (rv != SECSuccess) { - gWeakDHParamsRegisterError = PORT_GetError(); - } - return (PRStatus)rv; -} - -/* global init strategy inspired by ssl3_CreateECDHEphemeralKeys */ -SECStatus -SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled) -{ - sslSocket *ss; - PRStatus status; - - if (enabled) { - status = PR_CallOnce(&gWeakDHParamsRegisterOnce, - ssl3_WeakDHParamsRegisterShutdown); - if (status != PR_SUCCESS) { - PORT_SetError(gWeakDHParamsRegisterError); - return SECFailure; - } - - status = PR_CallOnce(&gWeakDHParamsOnce, ssl3_CreateWeakDHParams); - if (status != PR_SUCCESS) { - PORT_SetError(gWeakDHParamsError); - return SECFailure; - } - } - - if (!fd) - return SECSuccess; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DHEGroupPrefSet", SSL_GETPID(), fd)); - return SECFailure; - } - - ss->ssl3.dheWeakGroupEnabled = enabled; - return SECSuccess; -} - -SECStatus -SSL_GetChannelBinding(PRFileDesc *fd, - SSLChannelBindingType binding_type, - unsigned char *out, - unsigned int *outLen, - unsigned int outLenMax) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelBinding", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (binding_type != SSL_CHANNEL_BINDING_TLS_UNIQUE) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - - return ssl3_GetTLSUniqueChannelBinding(ss, out, outLen, outLenMax); -} - -#include "dhe-param.c" - -static const SSLDHEGroupType ssl_default_dhe_groups[] = { - ssl_ff_dhe_2048_group -}; - -/* Keep this array synchronized with the index definitions in SSLDHEGroupType */ -static const ssl3DHParams *all_ssl3DHParams[] = { - NULL, /* ssl_dhe_group_none */ - &ff_dhe_2048, - &ff_dhe_3072, - &ff_dhe_4096, - &ff_dhe_6144, - &ff_dhe_8192, -}; - -static SSLDHEGroupType -selectDHEGroup(sslSocket *ss, const SSLDHEGroupType *groups, PRUint16 num_groups) -{ - if (!groups || !num_groups) - return ssl_dhe_group_none; - - /* We don't have automatic group parameter selection yet - * (potentially) based on socket parameters, e.g. key sizes. - * For now, we return the first available group from the allowed list. */ - return groups[0]; -} - -/* Ensure DH parameters have been selected */ -SECStatus -ssl3_SelectDHParams(sslSocket *ss) -{ - SSLDHEGroupType selectedGroup = ssl_dhe_group_none; - - if (ss->ssl3.dheWeakGroupEnabled) { - ss->dheParams = gWeakDHParams; - } else { - if (ss->ssl3.dheGroups) { - selectedGroup = selectDHEGroup(ss, ss->ssl3.dheGroups, - ss->ssl3.numDHEGroups); - } else { - size_t number_of_default_groups = PR_ARRAY_SIZE(ssl_default_dhe_groups); - selectedGroup = selectDHEGroup(ss, ssl_default_dhe_groups, - number_of_default_groups); - } - - if (selectedGroup == ssl_dhe_group_none || - selectedGroup >= ssl_dhe_group_max) { - return SECFailure; - } - - ss->dheParams = all_ssl3DHParams[selectedGroup]; - } - - return SECSuccess; -} - -/* LOCKS ??? XXX */ -static PRFileDesc * -ssl_ImportFD(PRFileDesc *model, PRFileDesc *fd, SSLProtocolVariant variant) -{ - sslSocket *ns = NULL; - PRStatus rv; - PRNetAddr addr; - SECStatus status = ssl_Init(); - - if (status != SECSuccess) { - return NULL; - } - - if (model == NULL) { - /* Just create a default socket if we're given NULL for the model */ - ns = ssl_NewSocket((PRBool)(!ssl_defaults.noLocks), variant); - } else { - sslSocket *ss = ssl_FindSocket(model); - if (ss == NULL || ss->protocolVariant != variant) { - SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ImportFD", - SSL_GETPID(), model)); - return NULL; - } - ns = ssl_DupSocket(ss); - } - if (ns == NULL) - return NULL; - - rv = ssl_PushIOLayer(ns, fd, PR_TOP_IO_LAYER); - if (rv != PR_SUCCESS) { - ssl_FreeSocket(ns); - SET_ERROR_CODE - return NULL; - } -#if defined(DEBUG) || defined(FORCE_PR_ASSERT) - { - sslSocket *ss = ssl_FindSocket(fd); - PORT_Assert(ss == ns); - } -#endif - ns->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ns, &addr)); - return fd; -} - -PRFileDesc * -SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd) -{ - return ssl_ImportFD(model, fd, ssl_variant_stream); -} - -PRFileDesc * -DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd) -{ - return ssl_ImportFD(model, fd, ssl_variant_datagram); -} - -/* SSL_SetNextProtoCallback is used to select an application protocol - * for ALPN and NPN. For ALPN, this runs on the server; for NPN it - * runs on the client. */ -/* Note: The ALPN version doesn't allow for the use of a default, setting a - * status of SSL_NEXT_PROTO_NO_OVERLAP is treated as a failure. */ -SECStatus -SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback, - void *arg) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoCallback", SSL_GETPID(), - fd)); - return SECFailure; - } - - ssl_GetSSL3HandshakeLock(ss); - ss->nextProtoCallback = callback; - ss->nextProtoArg = arg; - ssl_ReleaseSSL3HandshakeLock(ss); - - return SECSuccess; -} - -/* ssl_NextProtoNegoCallback is set as an ALPN/NPN callback when - * SSL_SetNextProtoNego is used. - */ -static SECStatus -ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd, - const unsigned char *protos, unsigned int protos_len, - unsigned char *protoOut, unsigned int *protoOutLen, - unsigned int protoMaxLen) -{ - unsigned int i, j; - const unsigned char *result; - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in ssl_NextProtoNegoCallback", - SSL_GETPID(), fd)); - return SECFailure; - } - - /* For each protocol in server preference, see if we support it. */ - for (i = 0; i < protos_len;) { - for (j = 0; j < ss->opt.nextProtoNego.len;) { - if (protos[i] == ss->opt.nextProtoNego.data[j] && - PORT_Memcmp(&protos[i + 1], &ss->opt.nextProtoNego.data[j + 1], - protos[i]) == 0) { - /* We found a match. */ - ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED; - result = &protos[i]; - goto found; - } - j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j]; - } - i += 1 + (unsigned int)protos[i]; - } - - /* The other side supports the extension, and either doesn't have any - * protocols configured, or none of its options match ours. In this case we - * request our favoured protocol. */ - /* This will be treated as a failure for ALPN. */ - ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP; - result = ss->opt.nextProtoNego.data; - -found: - if (protoMaxLen < result[0]) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return SECFailure; - } - memcpy(protoOut, result + 1, result[0]); - *protoOutLen = result[0]; - return SECSuccess; -} - -SECStatus -SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data, - unsigned int length) -{ - sslSocket *ss; - SECStatus rv; - SECItem dataItem = { siBuffer, (unsigned char *)data, length }; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess) - return SECFailure; - - ssl_GetSSL3HandshakeLock(ss); - SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE); - rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &dataItem); - ssl_ReleaseSSL3HandshakeLock(ss); - - if (rv != SECSuccess) - return rv; - - return SSL_SetNextProtoCallback(fd, ssl_NextProtoNegoCallback, NULL); -} - -SECStatus -SSL_GetNextProto(PRFileDesc *fd, SSLNextProtoState *state, unsigned char *buf, - unsigned int *bufLen, unsigned int bufLenMax) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNextProto", SSL_GETPID(), - fd)); - return SECFailure; - } - - if (!state || !buf || !bufLen) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - *state = ss->ssl3.nextProtoState; - - if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT && - ss->ssl3.nextProto.data) { - if (ss->ssl3.nextProto.len > bufLenMax) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return SECFailure; - } - PORT_Memcpy(buf, ss->ssl3.nextProto.data, ss->ssl3.nextProto.len); - *bufLen = ss->ssl3.nextProto.len; - } else { - *bufLen = 0; - } - - return SECSuccess; -} - -SECStatus -SSL_SetSRTPCiphers(PRFileDesc *fd, - const PRUint16 *ciphers, - unsigned int numCiphers) -{ - sslSocket *ss; - unsigned int i; - - ss = ssl_FindSocket(fd); - if (!ss || !IS_DTLS(ss)) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSRTPCiphers", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (numCiphers > MAX_DTLS_SRTP_CIPHER_SUITES) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ss->ssl3.dtlsSRTPCipherCount = 0; - for (i = 0; i < numCiphers; i++) { - const PRUint16 *srtpCipher = srtpCiphers; - - while (*srtpCipher) { - if (ciphers[i] == *srtpCipher) - break; - srtpCipher++; - } - if (*srtpCipher) { - ss->ssl3.dtlsSRTPCiphers[ss->ssl3.dtlsSRTPCipherCount++] = - ciphers[i]; - } else { - SSL_DBG(("%d: SSL[%d]: invalid or unimplemented SRTP cipher " - "suite specified: 0x%04hx", - SSL_GETPID(), fd, - ciphers[i])); - } - } - - if (ss->ssl3.dtlsSRTPCipherCount == 0) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - return SECSuccess; -} - -SECStatus -SSL_GetSRTPCipher(PRFileDesc *fd, PRUint16 *cipher) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetSRTPCipher", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (!ss->ssl3.dtlsSRTPCipherSuite) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - *cipher = ss->ssl3.dtlsSRTPCipherSuite; - return SECSuccess; -} - -PRFileDesc * -SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) -{ - sslSocket *sm = NULL, *ss = NULL; - int i; - sslServerCerts *mc = NULL; - sslServerCerts *sc = NULL; - - if (model == NULL) { - PR_SetError(SEC_ERROR_INVALID_ARGS, 0); - return NULL; - } - sm = ssl_FindSocket(model); - if (sm == NULL) { - SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ReconfigFD", - SSL_GETPID(), model)); - return NULL; - } - ss = ssl_FindSocket(fd); - PORT_Assert(ss); - if (ss == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - - ss->opt = sm->opt; - ss->vrange = sm->vrange; - PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites); - PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, sm->ssl3.dtlsSRTPCiphers, - sizeof(PRUint16) * sm->ssl3.dtlsSRTPCipherCount); - ss->ssl3.dtlsSRTPCipherCount = sm->ssl3.dtlsSRTPCipherCount; - PORT_Memcpy(ss->ssl3.signatureAlgorithms, sm->ssl3.signatureAlgorithms, - sizeof(ss->ssl3.signatureAlgorithms[0]) * - sm->ssl3.signatureAlgorithmCount); - ss->ssl3.signatureAlgorithmCount = sm->ssl3.signatureAlgorithmCount; - ss->ssl3.downgradeCheckVersion = sm->ssl3.downgradeCheckVersion; - - if (!ss->opt.useSecurity) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - /* This int should be SSLKEAType, but CC on Irix complains, - * during the for loop. - */ - for (i = kt_null; i < kt_kea_size; i++) { - mc = &(sm->serverCerts[i]); - sc = &(ss->serverCerts[i]); - if (mc->serverCert && mc->serverCertChain) { - if (sc->serverCert) { - CERT_DestroyCertificate(sc->serverCert); - } - sc->serverCert = CERT_DupCertificate(mc->serverCert); - if (sc->serverCertChain) { - CERT_DestroyCertificateList(sc->serverCertChain); - } - sc->serverCertChain = CERT_DupCertList(mc->serverCertChain); - if (!sc->serverCertChain) - goto loser; - if (sm->certStatusArray[i]) { - if (ss->certStatusArray[i]) { - SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE); - ss->certStatusArray[i] = NULL; - } - ss->certStatusArray[i] = SECITEM_DupArray(NULL, sm->certStatusArray[i]); - if (!ss->certStatusArray[i]) - goto loser; - } - if (sm->signedCertTimestamps[i].data) { - if (ss->signedCertTimestamps[i].data) { - SECITEM_FreeItem(&ss->signedCertTimestamps[i], PR_FALSE); - } - if (SECITEM_CopyItem(NULL, - &ss->signedCertTimestamps[i], - &sm->signedCertTimestamps[i]) != - SECSuccess) { - goto loser; - } - } - } - if (mc->serverKeyPair) { - if (sc->serverKeyPair) { - ssl3_FreeKeyPair(sc->serverKeyPair); - } - sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair); - sc->serverKeyBits = mc->serverKeyBits; - } - } - if (sm->stepDownKeyPair) { - if (ss->stepDownKeyPair) { - ssl3_FreeKeyPair(ss->stepDownKeyPair); - } - ss->stepDownKeyPair = ssl3_GetKeyPairRef(sm->stepDownKeyPair); - } - if (sm->ephemeralECDHKeyPair) { - if (ss->ephemeralECDHKeyPair) { - ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); - } - ss->ephemeralECDHKeyPair = - ssl3_GetKeyPairRef(sm->ephemeralECDHKeyPair); - } - /* copy trust anchor names */ - if (sm->ssl3.ca_list) { - if (ss->ssl3.ca_list) { - CERT_FreeDistNames(ss->ssl3.ca_list); - } - ss->ssl3.ca_list = CERT_DupDistNames(sm->ssl3.ca_list); - if (!ss->ssl3.ca_list) { - goto loser; - } - } - - if (sm->authCertificate) - ss->authCertificate = sm->authCertificate; - if (sm->authCertificateArg) - ss->authCertificateArg = sm->authCertificateArg; - if (sm->getClientAuthData) - ss->getClientAuthData = sm->getClientAuthData; - if (sm->getClientAuthDataArg) - ss->getClientAuthDataArg = sm->getClientAuthDataArg; - if (sm->sniSocketConfig) - ss->sniSocketConfig = sm->sniSocketConfig; - if (sm->sniSocketConfigArg) - ss->sniSocketConfigArg = sm->sniSocketConfigArg; - if (sm->handleBadCert) - ss->handleBadCert = sm->handleBadCert; - if (sm->badCertArg) - ss->badCertArg = sm->badCertArg; - if (sm->handshakeCallback) - ss->handshakeCallback = sm->handshakeCallback; - if (sm->handshakeCallbackData) - ss->handshakeCallbackData = sm->handshakeCallbackData; - if (sm->pkcs11PinArg) - ss->pkcs11PinArg = sm->pkcs11PinArg; - if (sm->getChannelID) - ss->getChannelID = sm->getChannelID; - if (sm->getChannelIDArg) - ss->getChannelIDArg = sm->getChannelIDArg; - return fd; -loser: - return NULL; -} - -/* - * Get the user supplied range - */ -static SECStatus -ssl3_GetRangePolicy(SSLProtocolVariant protocolVariant, SSLVersionRange *prange) -{ - SECStatus rv; - PRUint32 policy; - PRInt32 option; - - /* only use policy constraints if we've set the apply ssl policy bit */ - rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy); - if ((rv != SECSuccess) || !(policy & NSS_USE_POLICY_IN_SSL)) { - return SECFailure; - } - rv = NSS_OptionGet(VERSIONS_POLICY_MIN(protocolVariant), &option); - if (rv != SECSuccess) { - return rv; - } - prange->min = (PRUint16)option; - rv = NSS_OptionGet(VERSIONS_POLICY_MAX(protocolVariant), &option); - if (rv != SECSuccess) { - return rv; - } - prange->max = (PRUint16)option; - if (prange->max < prange->min) { - return SECFailure; /* don't accept an invalid policy */ - } - return SECSuccess; -} - -/* - * Constrain a single protocol variant's range based on the user policy - */ -static SECStatus -ssl3_ConstrainVariantRangeByPolicy(SSLProtocolVariant protocolVariant) -{ - SSLVersionRange vrange; - SSLVersionRange pvrange; - SECStatus rv; - - vrange = *VERSIONS_DEFAULTS(protocolVariant); - rv = ssl3_GetRangePolicy(protocolVariant, &pvrange); - if (rv != SECSuccess) { - return SECSuccess; /* we don't have any policy */ - } - vrange.min = PR_MAX(vrange.min, pvrange.min); - vrange.max = PR_MIN(vrange.max, pvrange.max); - if (vrange.max >= vrange.min) { - *VERSIONS_DEFAULTS(protocolVariant) = vrange; - } else { - /* there was no overlap, turn off range altogether */ - pvrange.min = pvrange.max = SSL_LIBRARY_VERSION_NONE; - *VERSIONS_DEFAULTS(protocolVariant) = pvrange; - } - return SECSuccess; -} - -static PRBool -ssl_VersionIsSupportedByPolicy(SSLProtocolVariant protocolVariant, - SSL3ProtocolVersion version) -{ - SSLVersionRange pvrange; - SECStatus rv; - - rv = ssl3_GetRangePolicy(protocolVariant, &pvrange); - if (rv == SECSuccess) { - if ((version > pvrange.max) || (version < pvrange.min)) { - return PR_FALSE; /* disallowed by policy */ - } - } - return PR_TRUE; -} - -/* - * This is called at SSL init time to constrain the existing range based - * on user supplied policy. - */ -SECStatus -ssl3_ConstrainRangeByPolicy(void) -{ - SECStatus rv; - rv = ssl3_ConstrainVariantRangeByPolicy(ssl_variant_stream); - if (rv != SECSuccess) { - return rv; - } - rv = ssl3_ConstrainVariantRangeByPolicy(ssl_variant_datagram); - if (rv != SECSuccess) { - return rv; - } - return SECSuccess; -} - -PRBool -ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant, - SSL3ProtocolVersion version) -{ - if (!ssl_VersionIsSupportedByPolicy(protocolVariant, version)) { - return PR_FALSE; - } - switch (protocolVariant) { - case ssl_variant_stream: - return (version >= SSL_LIBRARY_VERSION_3_0 && - version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED); - case ssl_variant_datagram: - return (version >= SSL_LIBRARY_VERSION_TLS_1_1 && - version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED); - default: - /* Can't get here */ - PORT_Assert(PR_FALSE); - return PR_FALSE; - } -} - -/* Returns PR_TRUE if the given version range is valid and -** fully supported; otherwise, returns PR_FALSE. -*/ -static PRBool -ssl3_VersionRangeIsValid(SSLProtocolVariant protocolVariant, - const SSLVersionRange *vrange) -{ - return vrange && - vrange->min <= vrange->max && - ssl3_VersionIsSupported(protocolVariant, vrange->min) && - ssl3_VersionIsSupported(protocolVariant, vrange->max); -} - -const SECItem * -SSL_PeerSignedCertTimestamps(PRFileDesc *fd) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_PeerSignedCertTimestamps", - SSL_GETPID(), fd)); - return NULL; - } - - if (!ss->sec.ci.sid) { - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return NULL; - } - - if (ss->sec.ci.sid->version < SSL_LIBRARY_VERSION_3_0) { - PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); - return NULL; - } - return &ss->sec.ci.sid->u.ssl3.signedCertTimestamps; -} - -SECStatus -SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant, - SSLVersionRange *vrange) -{ - if (!vrange) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - switch (protocolVariant) { - case ssl_variant_stream: - vrange->min = SSL_LIBRARY_VERSION_3_0; - vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED; - break; - case ssl_variant_datagram: - vrange->min = SSL_LIBRARY_VERSION_TLS_1_1; - vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED; - break; - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - return SECSuccess; -} - -SECStatus -SSL_VersionRangeGetDefault(SSLProtocolVariant protocolVariant, - SSLVersionRange *vrange) -{ - if ((protocolVariant != ssl_variant_stream && - protocolVariant != ssl_variant_datagram) || - !vrange) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - *vrange = *VERSIONS_DEFAULTS(protocolVariant); - - return SECSuccess; -} - -SECStatus -SSL_VersionRangeSetDefault(SSLProtocolVariant protocolVariant, - const SSLVersionRange *vrange) -{ - if (!ssl3_VersionRangeIsValid(protocolVariant, vrange)) { - PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); - return SECFailure; - } - - *VERSIONS_DEFAULTS(protocolVariant) = *vrange; - - return SECSuccess; -} - -SECStatus -SSL_VersionRangeGet(PRFileDesc *fd, SSLVersionRange *vrange) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_VersionRangeGet", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (!vrange) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - *vrange = ss->vrange; - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return SECSuccess; -} - -SECStatus -SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_VersionRangeSet", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (!ssl3_VersionRangeIsValid(ss->protocolVariant, vrange)) { - PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (ss->ssl3.downgradeCheckVersion && - ss->vrange.max > ss->ssl3.downgradeCheckVersion) { - PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - return SECFailure; - } - - ss->vrange = *vrange; - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return SECSuccess; -} - -SECStatus -SSL_SetDowngradeCheckVersion(PRFileDesc *fd, PRUint16 version) -{ - sslSocket *ss = ssl_FindSocket(fd); - SECStatus rv = SECFailure; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetDowngradeCheckVersion", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (version && !ssl3_VersionIsSupported(ss->protocolVariant, version)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - if (version && version < ss->vrange.max) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - goto loser; - } - ss->ssl3.downgradeCheckVersion = version; - rv = SECSuccess; - -loser: - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - - return rv; -} - -const SECItemArray * -SSL_PeerStapledOCSPResponses(PRFileDesc *fd) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_PeerStapledOCSPResponses", - SSL_GETPID(), fd)); - return NULL; - } - - if (!ss->sec.ci.sid) { - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return NULL; - } - - return &ss->sec.ci.sid->peerCertStatus; -} - -SECStatus -SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_HandshakeResumedSession", - SSL_GETPID(), fd)); - return SECFailure; - } - - *handshake_resumed = ss->ssl3.hs.isResuming; - return SECSuccess; -} - -const SECItem * -SSL_GetRequestedClientCertificateTypes(PRFileDesc *fd) -{ - sslSocket *ss = ssl_FindSocket(fd); - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in " - "SSL_GetRequestedClientCertificateTypes", - SSL_GETPID(), fd)); - return NULL; - } - - return ss->requestedCertTypes; -} - -/************************************************************************/ -/* The following functions are the TOP LEVEL SSL functions. -** They all get called through the NSPRIOMethods table below. -*/ - -static PRFileDesc *PR_CALLBACK -ssl_Accept(PRFileDesc *fd, PRNetAddr *sockaddr, PRIntervalTime timeout) -{ - sslSocket *ss; - sslSocket *ns = NULL; - PRFileDesc *newfd = NULL; - PRFileDesc *osfd; - PRStatus status; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in accept", SSL_GETPID(), fd)); - return NULL; - } - - /* IF this is a listen socket, there shouldn't be any I/O going on */ - SSL_LOCK_READER(ss); - SSL_LOCK_WRITER(ss); - ssl_Get1stHandshakeLock(ss); - ssl_GetSSL3HandshakeLock(ss); - - ss->cTimeout = timeout; - - osfd = ss->fd->lower; - - /* First accept connection */ - newfd = osfd->methods->accept(osfd, sockaddr, timeout); - if (newfd == NULL) { - SSL_DBG(("%d: SSL[%d]: accept failed, errno=%d", - SSL_GETPID(), ss->fd, PORT_GetError())); - } else { - /* Create ssl module */ - ns = ssl_DupSocket(ss); - } - - ssl_ReleaseSSL3HandshakeLock(ss); - ssl_Release1stHandshakeLock(ss); - SSL_UNLOCK_WRITER(ss); - SSL_UNLOCK_READER(ss); /* ss isn't used below here. */ - - if (ns == NULL) - goto loser; - - /* push ssl module onto the new socket */ - status = ssl_PushIOLayer(ns, newfd, PR_TOP_IO_LAYER); - if (status != PR_SUCCESS) - goto loser; - - /* Now start server connection handshake with client. - ** Don't need locks here because nobody else has a reference to ns yet. - */ - if (ns->opt.useSecurity) { - if (ns->opt.handshakeAsClient) { - ns->handshake = ssl2_BeginClientHandshake; - ss->handshaking = sslHandshakingAsClient; - } else { - ns->handshake = ssl2_BeginServerHandshake; - ss->handshaking = sslHandshakingAsServer; - } - } - ns->TCPconnected = 1; - return newfd; - -loser: - if (ns != NULL) - ssl_FreeSocket(ns); - if (newfd != NULL) - PR_Close(newfd); - return NULL; -} - -static PRStatus PR_CALLBACK -ssl_Connect(PRFileDesc *fd, const PRNetAddr *sockaddr, PRIntervalTime timeout) -{ - sslSocket *ss; - PRStatus rv; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in connect", SSL_GETPID(), fd)); - return PR_FAILURE; - } - - /* IF this is a listen socket, there shouldn't be any I/O going on */ - SSL_LOCK_READER(ss); - SSL_LOCK_WRITER(ss); - - ss->cTimeout = timeout; - rv = (PRStatus)(*ss->ops->connect)(ss, sockaddr); - - SSL_UNLOCK_WRITER(ss); - SSL_UNLOCK_READER(ss); - - return rv; -} - -static PRStatus PR_CALLBACK -ssl_Bind(PRFileDesc *fd, const PRNetAddr *addr) -{ - sslSocket *ss = ssl_GetPrivate(fd); - PRStatus rv; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in bind", SSL_GETPID(), fd)); - return PR_FAILURE; - } - SSL_LOCK_READER(ss); - SSL_LOCK_WRITER(ss); - - rv = (PRStatus)(*ss->ops->bind)(ss, addr); - - SSL_UNLOCK_WRITER(ss); - SSL_UNLOCK_READER(ss); - return rv; -} - -static PRStatus PR_CALLBACK -ssl_Listen(PRFileDesc *fd, PRIntn backlog) -{ - sslSocket *ss = ssl_GetPrivate(fd); - PRStatus rv; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in listen", SSL_GETPID(), fd)); - return PR_FAILURE; - } - SSL_LOCK_READER(ss); - SSL_LOCK_WRITER(ss); - - rv = (PRStatus)(*ss->ops->listen)(ss, backlog); - - SSL_UNLOCK_WRITER(ss); - SSL_UNLOCK_READER(ss); - return rv; -} - -static PRStatus PR_CALLBACK -ssl_Shutdown(PRFileDesc *fd, PRIntn how) -{ - sslSocket *ss = ssl_GetPrivate(fd); - PRStatus rv; - - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in shutdown", SSL_GETPID(), fd)); - return PR_FAILURE; - } - if (how == PR_SHUTDOWN_RCV || how == PR_SHUTDOWN_BOTH) { - SSL_LOCK_READER(ss); - } - if (how == PR_SHUTDOWN_SEND || how == PR_SHUTDOWN_BOTH) { - SSL_LOCK_WRITER(ss); - } - - rv = (PRStatus)(*ss->ops->shutdown)(ss, how); - - if (how == PR_SHUTDOWN_SEND || how == PR_SHUTDOWN_BOTH) { - SSL_UNLOCK_WRITER(ss); - } - if (how == PR_SHUTDOWN_RCV || how == PR_SHUTDOWN_BOTH) { - SSL_UNLOCK_READER(ss); - } - return rv; -} - -static PRStatus PR_CALLBACK -ssl_Close(PRFileDesc *fd) -{ - sslSocket *ss; - PRStatus rv; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in close", SSL_GETPID(), fd)); - return PR_FAILURE; - } - - /* There must not be any I/O going on */ - SSL_LOCK_READER(ss); - SSL_LOCK_WRITER(ss); - - /* By the time this function returns, - ** ss is an invalid pointer, and the locks to which it points have - ** been unlocked and freed. So, this is the ONE PLACE in all of SSL - ** where the LOCK calls and the corresponding UNLOCK calls are not in - ** the same function scope. The unlock calls are in ssl_FreeSocket(). - */ - rv = (PRStatus)(*ss->ops->close)(ss); - - return rv; -} - -static int PR_CALLBACK -ssl_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, - PRIntervalTime timeout) -{ - sslSocket *ss; - int rv; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in recv", SSL_GETPID(), fd)); - return SECFailure; - } - SSL_LOCK_READER(ss); - ss->rTimeout = timeout; - if (!ss->opt.fdx) - ss->wTimeout = timeout; - rv = (*ss->ops->recv)(ss, (unsigned char *)buf, len, flags); - SSL_UNLOCK_READER(ss); - return rv; -} - -static int PR_CALLBACK -ssl_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags, - PRIntervalTime timeout) -{ - sslSocket *ss; - int rv; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in send", SSL_GETPID(), fd)); - return SECFailure; - } - SSL_LOCK_WRITER(ss); - ss->wTimeout = timeout; - if (!ss->opt.fdx) - ss->rTimeout = timeout; - rv = (*ss->ops->send)(ss, (const unsigned char *)buf, len, flags); - SSL_UNLOCK_WRITER(ss); - return rv; -} - -static int PR_CALLBACK -ssl_Read(PRFileDesc *fd, void *buf, PRInt32 len) -{ - sslSocket *ss; - int rv; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in read", SSL_GETPID(), fd)); - return SECFailure; - } - SSL_LOCK_READER(ss); - ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; - if (!ss->opt.fdx) - ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; - rv = (*ss->ops->read)(ss, (unsigned char *)buf, len); - SSL_UNLOCK_READER(ss); - return rv; -} - -static int PR_CALLBACK -ssl_Write(PRFileDesc *fd, const void *buf, PRInt32 len) -{ - sslSocket *ss; - int rv; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in write", SSL_GETPID(), fd)); - return SECFailure; - } - SSL_LOCK_WRITER(ss); - ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; - if (!ss->opt.fdx) - ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; - rv = (*ss->ops->write)(ss, (const unsigned char *)buf, len); - SSL_UNLOCK_WRITER(ss); - return rv; -} - -static PRStatus PR_CALLBACK -ssl_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) -{ - sslSocket *ss; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in getpeername", SSL_GETPID(), fd)); - return PR_FAILURE; - } - return (PRStatus)(*ss->ops->getpeername)(ss, addr); -} - -/* -*/ -SECStatus -ssl_GetPeerInfo(sslSocket *ss) -{ - PRFileDesc *osfd; - int rv; - PRNetAddr sin; - - osfd = ss->fd->lower; - - PORT_Memset(&sin, 0, sizeof(sin)); - rv = osfd->methods->getpeername(osfd, &sin); - if (rv < 0) { - return SECFailure; - } - ss->TCPconnected = 1; - if (sin.inet.family == PR_AF_INET) { - PR_ConvertIPv4AddrToIPv6(sin.inet.ip, &ss->sec.ci.peer); - ss->sec.ci.port = sin.inet.port; - } else if (sin.ipv6.family == PR_AF_INET6) { - ss->sec.ci.peer = sin.ipv6.ip; - ss->sec.ci.port = sin.ipv6.port; - } else { - PORT_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR); - return SECFailure; - } - return SECSuccess; -} - -static PRStatus PR_CALLBACK -ssl_GetSockName(PRFileDesc *fd, PRNetAddr *name) -{ - sslSocket *ss; - - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in getsockname", SSL_GETPID(), fd)); - return PR_FAILURE; - } - return (PRStatus)(*ss->ops->getsockname)(ss, name); -} - -SECStatus -SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, - SSLKEAType kea) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetStapledOCSPResponses", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (kea <= 0 || kea >= kt_kea_size) { - SSL_DBG(("%d: SSL[%d]: invalid key type in SSL_SetStapledOCSPResponses", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (ss->certStatusArray[kea]) { - SECITEM_FreeArray(ss->certStatusArray[kea], PR_TRUE); - ss->certStatusArray[kea] = NULL; - } - if (responses) { - ss->certStatusArray[kea] = SECITEM_DupArray(NULL, responses); - } - return (ss->certStatusArray[kea] || !responses) ? SECSuccess : SECFailure; -} - -SECStatus -SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, SSLKEAType kea) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSignedCertTimestamps", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (kea <= 0 || kea >= kt_kea_size) { - SSL_DBG(("%d: SSL[%d]: invalid key type in SSL_SetSignedCertTimestamps", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (ss->signedCertTimestamps[kea].data) { - SECITEM_FreeItem(&ss->signedCertTimestamps[kea], PR_FALSE); - } - - if (!scts) { - return SECSuccess; - } - - return SECITEM_CopyItem(NULL, &ss->signedCertTimestamps[kea], scts); -} - -SECStatus -SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID) -{ - sslSocket *ss; - - ss = ssl_FindSocket(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSockPeerID", - SSL_GETPID(), fd)); - return SECFailure; - } - - if (ss->peerID) { - PORT_Free(ss->peerID); - ss->peerID = NULL; - } - if (peerID) - ss->peerID = PORT_Strdup(peerID); - return (ss->peerID || !peerID) ? SECSuccess : SECFailure; -} - -#define PR_POLL_RW (PR_POLL_WRITE | PR_POLL_READ) - -static PRInt16 PR_CALLBACK -ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags) -{ - sslSocket *ss; - PRInt16 new_flags = how_flags; /* should select on these flags. */ - PRNetAddr addr; - - *p_out_flags = 0; - ss = ssl_GetPrivate(fd); - if (!ss) { - SSL_DBG(("%d: SSL[%d]: bad socket in SSL_Poll", - SSL_GETPID(), fd)); - return 0; /* don't poll on this socket */ - } - - if (ss->opt.useSecurity && - ss->handshaking != sslHandshakingUndetermined && - !ss->firstHsDone && - (how_flags & PR_POLL_RW)) { - if (!ss->TCPconnected) { - ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); - } - /* If it's not connected, then presumably the application is polling - ** on read or write appropriately, so don't change it. - */ - if (ss->TCPconnected) { - if (!ss->handshakeBegun) { - /* If the handshake has not begun, poll on read or write - ** based on the local application's role in the handshake, - ** not based on what the application requested. - */ - new_flags &= ~PR_POLL_RW; - if (ss->handshaking == sslHandshakingAsClient) { - new_flags |= PR_POLL_WRITE; - } else { /* handshaking as server */ - new_flags |= PR_POLL_READ; - } - } else - /* First handshake is in progress */ - if (ss->lastWriteBlocked) { - if (new_flags & PR_POLL_READ) { - /* The caller is waiting for data to be received, - ** but the initial handshake is blocked on write, or the - ** client's first handshake record has not been written. - ** The code should select on write, not read. - */ - new_flags ^= PR_POLL_READ; /* don't select on read. */ - new_flags |= PR_POLL_WRITE; /* do select on write. */ - } - } else if (new_flags & PR_POLL_WRITE) { - /* The caller is trying to write, but the handshake is - ** blocked waiting for data to read, and the first - ** handshake has been sent. So do NOT to poll on write - ** unless we did false start. - */ - if (!(ss->version >= SSL_LIBRARY_VERSION_3_0 && - ss->ssl3.hs.canFalseStart)) { - new_flags ^= PR_POLL_WRITE; /* don't select on write. */ - } - new_flags |= PR_POLL_READ; /* do select on read. */ - } - } - } else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) { - *p_out_flags = PR_POLL_READ; /* it's ready already. */ - return new_flags; - } else if ((ss->lastWriteBlocked) && (how_flags & PR_POLL_READ) && - (ss->pendingBuf.len != 0)) { /* write data waiting to be sent */ - new_flags |= PR_POLL_WRITE; /* also select on write. */ - } - - if (ss->version >= SSL_LIBRARY_VERSION_3_0 && - ss->ssl3.hs.restartTarget != NULL) { - /* Read and write will block until the asynchronous callback completes - * (e.g. until SSL_AuthCertificateComplete is called), so don't tell - * the caller to poll the socket unless there is pending write data. - */ - if (ss->lastWriteBlocked && ss->pendingBuf.len != 0) { - /* Ignore any newly-received data on the socket, but do wait for - * the socket to become writable again. Here, it is OK for an error - * to be detected, because our logic for sending pending write data - * will allow us to report the error to the caller without the risk - * of the application spinning. - */ - new_flags &= (PR_POLL_WRITE | PR_POLL_EXCEPT); - } else { - /* Unfortunately, clearing new_flags will make it impossible for - * the application to detect errors that it would otherwise be - * able to detect with PR_POLL_EXCEPT, until the asynchronous - * callback completes. However, we must clear all the flags to - * prevent the application from spinning (alternating between - * calling PR_Poll that would return PR_POLL_EXCEPT, and send/recv - * which won't actually report the I/O error while we are waiting - * for the asynchronous callback to complete). - */ - new_flags = 0; - } - } - - if (new_flags && (fd->lower->methods->poll != NULL)) { - PRInt16 lower_out_flags = 0; - PRInt16 lower_new_flags; - lower_new_flags = fd->lower->methods->poll(fd->lower, new_flags, - &lower_out_flags); - if ((lower_new_flags & lower_out_flags) && (how_flags != new_flags)) { - PRInt16 out_flags = lower_out_flags & ~PR_POLL_RW; - if (lower_out_flags & PR_POLL_READ) - out_flags |= PR_POLL_WRITE; - if (lower_out_flags & PR_POLL_WRITE) - out_flags |= PR_POLL_READ; - *p_out_flags = out_flags; - new_flags = how_flags; - } else { - *p_out_flags = lower_out_flags; - new_flags = lower_new_flags; - } - } - - return new_flags; -} - -static PRInt32 PR_CALLBACK -ssl_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, - const void *headers, PRInt32 hlen, - PRTransmitFileFlags flags, PRIntervalTime timeout) -{ - PRSendFileData sfd; - - sfd.fd = fd; - sfd.file_offset = 0; - sfd.file_nbytes = 0; - sfd.header = headers; - sfd.hlen = hlen; - sfd.trailer = NULL; - sfd.tlen = 0; - - return sd->methods->sendfile(sd, &sfd, flags, timeout); -} - -PRBool -ssl_FdIsBlocking(PRFileDesc *fd) -{ - PRSocketOptionData opt; - PRStatus status; - - opt.option = PR_SockOpt_Nonblocking; - opt.value.non_blocking = PR_FALSE; - status = PR_GetSocketOption(fd, &opt); - if (status != PR_SUCCESS) - return PR_FALSE; - return (PRBool)!opt.value.non_blocking; -} - -PRBool -ssl_SocketIsBlocking(sslSocket *ss) -{ - return ssl_FdIsBlocking(ss->fd); -} - -PRInt32 sslFirstBufSize = 8 * 1024; -PRInt32 sslCopyLimit = 1024; - -static PRInt32 PR_CALLBACK -ssl_WriteV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 vectors, - PRIntervalTime timeout) -{ - PRInt32 i; - PRInt32 bufLen; - PRInt32 left; - PRInt32 rv; - PRInt32 sent = 0; - const PRInt32 first_len = sslFirstBufSize; - const PRInt32 limit = sslCopyLimit; - PRBool blocking; - PRIOVec myIov = { 0, 0 }; - char buf[MAX_FRAGMENT_LENGTH]; - - if (vectors < 0) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return -1; - } - if (vectors > PR_MAX_IOVECTOR_SIZE) { - PORT_SetError(PR_BUFFER_OVERFLOW_ERROR); - return -1; - } - for (i = 0; i < vectors; i++) { - if (iov[i].iov_len < 0) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return -1; - } - } - blocking = ssl_FdIsBlocking(fd); - -#define K16 sizeof(buf) -#define KILL_VECTORS \ - while (vectors && !iov->iov_len) { \ - ++iov; \ - --vectors; \ - } -#define GET_VECTOR \ - do { \ - myIov = *iov++; \ - --vectors; \ - KILL_VECTORS \ - } while (0) -#define HANDLE_ERR(rv, len) \ - if (rv != len) { \ - if (rv < 0) { \ - if (!blocking && \ - (PR_GetError() == PR_WOULD_BLOCK_ERROR) && \ - (sent > 0)) { \ - return sent; \ - } else { \ - return -1; \ - } \ - } \ - /* Only a nonblocking socket can have partial sends */ \ - PR_ASSERT(!blocking); \ - return sent + rv; \ - } -#define SEND(bfr, len) \ - do { \ - rv = ssl_Send(fd, bfr, len, 0, timeout); \ - HANDLE_ERR(rv, len) \ - sent += len; \ - } while (0) - - /* Make sure the first write is at least 8 KB, if possible. */ - KILL_VECTORS - if (!vectors) - return ssl_Send(fd, 0, 0, 0, timeout); - GET_VECTOR; - if (!vectors) { - return ssl_Send(fd, myIov.iov_base, myIov.iov_len, 0, timeout); - } - if (myIov.iov_len < first_len) { - PORT_Memcpy(buf, myIov.iov_base, myIov.iov_len); - bufLen = myIov.iov_len; - left = first_len - bufLen; - while (vectors && left) { - int toCopy; - GET_VECTOR; - toCopy = PR_MIN(left, myIov.iov_len); - PORT_Memcpy(buf + bufLen, myIov.iov_base, toCopy); - bufLen += toCopy; - left -= toCopy; - myIov.iov_base += toCopy; - myIov.iov_len -= toCopy; - } - SEND(buf, bufLen); - } - - while (vectors || myIov.iov_len) { - PRInt32 addLen; - if (!myIov.iov_len) { - GET_VECTOR; - } - while (myIov.iov_len >= K16) { - SEND(myIov.iov_base, K16); - myIov.iov_base += K16; - myIov.iov_len -= K16; - } - if (!myIov.iov_len) - continue; - - if (!vectors || myIov.iov_len > limit) { - addLen = 0; - } else if ((addLen = iov->iov_len % K16) + myIov.iov_len <= limit) { - /* Addlen is already computed. */; - } else if (vectors > 1 && - iov[1].iov_len % K16 + addLen + myIov.iov_len <= 2 * limit) { - addLen = limit - myIov.iov_len; - } else - addLen = 0; - - if (!addLen) { - SEND(myIov.iov_base, myIov.iov_len); - myIov.iov_len = 0; - continue; - } - PORT_Memcpy(buf, myIov.iov_base, myIov.iov_len); - bufLen = myIov.iov_len; - do { - GET_VECTOR; - PORT_Memcpy(buf + bufLen, myIov.iov_base, addLen); - myIov.iov_base += addLen; - myIov.iov_len -= addLen; - bufLen += addLen; - - left = PR_MIN(limit, K16 - bufLen); - if (!vectors /* no more left */ - || myIov.iov_len > 0 /* we didn't use that one all up */ - || bufLen >= K16 /* it's full. */) { - addLen = 0; - } else if ((addLen = iov->iov_len % K16) <= left) { - /* Addlen is already computed. */; - } else if (vectors > 1 && - iov[1].iov_len % K16 + addLen <= left + limit) { - addLen = left; - } else - addLen = 0; - - } while (addLen); - SEND(buf, bufLen); - } - return sent; -} - -/* - * These functions aren't implemented. - */ - -static PRInt32 PR_CALLBACK -ssl_Available(PRFileDesc *fd) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return SECFailure; -} - -static PRInt64 PR_CALLBACK -ssl_Available64(PRFileDesc *fd) -{ - PRInt64 res; - - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - LL_I2L(res, -1L); - return res; -} - -static PRStatus PR_CALLBACK -ssl_FSync(PRFileDesc *fd) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return PR_FAILURE; -} - -static PRInt32 PR_CALLBACK -ssl_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence how) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return SECFailure; -} - -static PRInt64 PR_CALLBACK -ssl_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence how) -{ - PRInt64 res; - - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - LL_I2L(res, -1L); - return res; -} - -static PRStatus PR_CALLBACK -ssl_FileInfo(PRFileDesc *fd, PRFileInfo *info) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return PR_FAILURE; -} - -static PRStatus PR_CALLBACK -ssl_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return PR_FAILURE; -} - -static PRInt32 PR_CALLBACK -ssl_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, - PRNetAddr *addr, PRIntervalTime timeout) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return SECFailure; -} - -static PRInt32 PR_CALLBACK -ssl_SendTo(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, - const PRNetAddr *addr, PRIntervalTime timeout) -{ - PORT_Assert(0); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return SECFailure; -} - -static const PRIOMethods ssl_methods = { - PR_DESC_LAYERED, - ssl_Close, /* close */ - ssl_Read, /* read */ - ssl_Write, /* write */ - ssl_Available, /* available */ - ssl_Available64, /* available64 */ - ssl_FSync, /* fsync */ - ssl_Seek, /* seek */ - ssl_Seek64, /* seek64 */ - ssl_FileInfo, /* fileInfo */ - ssl_FileInfo64, /* fileInfo64 */ - ssl_WriteV, /* writev */ - ssl_Connect, /* connect */ - ssl_Accept, /* accept */ - ssl_Bind, /* bind */ - ssl_Listen, /* listen */ - ssl_Shutdown, /* shutdown */ - ssl_Recv, /* recv */ - ssl_Send, /* send */ - ssl_RecvFrom, /* recvfrom */ - ssl_SendTo, /* sendto */ - ssl_Poll, /* poll */ - PR_EmulateAcceptRead, /* acceptread */ - ssl_TransmitFile, /* transmitfile */ - ssl_GetSockName, /* getsockname */ - ssl_GetPeerName, /* getpeername */ - NULL, /* getsockopt OBSOLETE */ - NULL, /* setsockopt OBSOLETE */ - NULL, /* getsocketoption */ - NULL, /* setsocketoption */ - PR_EmulateSendFile, /* Send a (partial) file with header/trailer*/ - NULL, /* reserved for future use */ - NULL, /* reserved for future use */ - NULL, /* reserved for future use */ - NULL, /* reserved for future use */ - NULL /* reserved for future use */ -}; - -static PRIOMethods combined_methods; - -static void -ssl_SetupIOMethods(void) -{ - PRIOMethods *new_methods = &combined_methods; - const PRIOMethods *nspr_methods = PR_GetDefaultIOMethods(); - const PRIOMethods *my_methods = &ssl_methods; - - *new_methods = *nspr_methods; - - new_methods->file_type = my_methods->file_type; - new_methods->close = my_methods->close; - new_methods->read = my_methods->read; - new_methods->write = my_methods->write; - new_methods->available = my_methods->available; - new_methods->available64 = my_methods->available64; - new_methods->fsync = my_methods->fsync; - new_methods->seek = my_methods->seek; - new_methods->seek64 = my_methods->seek64; - new_methods->fileInfo = my_methods->fileInfo; - new_methods->fileInfo64 = my_methods->fileInfo64; - new_methods->writev = my_methods->writev; - new_methods->connect = my_methods->connect; - new_methods->accept = my_methods->accept; - new_methods->bind = my_methods->bind; - new_methods->listen = my_methods->listen; - new_methods->shutdown = my_methods->shutdown; - new_methods->recv = my_methods->recv; - new_methods->send = my_methods->send; - new_methods->recvfrom = my_methods->recvfrom; - new_methods->sendto = my_methods->sendto; - new_methods->poll = my_methods->poll; - new_methods->acceptread = my_methods->acceptread; - new_methods->transmitfile = my_methods->transmitfile; - new_methods->getsockname = my_methods->getsockname; - new_methods->getpeername = my_methods->getpeername; - /* new_methods->getsocketoption = my_methods->getsocketoption; */ - /* new_methods->setsocketoption = my_methods->setsocketoption; */ - new_methods->sendfile = my_methods->sendfile; -} - -static PRCallOnceType initIoLayerOnce; - -static PRStatus -ssl_InitIOLayer(void) -{ - ssl_layer_id = PR_GetUniqueIdentity("SSL"); - ssl_SetupIOMethods(); - ssl_inited = PR_TRUE; - return PR_SUCCESS; -} - -static PRStatus -ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id) -{ - PRFileDesc *layer = NULL; - PRStatus status; - - if (!ssl_inited) { - status = PR_CallOnce(&initIoLayerOnce, &ssl_InitIOLayer); - if (status != PR_SUCCESS) - goto loser; - } - - if (ns == NULL) - goto loser; - - layer = PR_CreateIOLayerStub(ssl_layer_id, &combined_methods); - if (layer == NULL) - goto loser; - layer->secret = (PRFilePrivate *)ns; - - /* Here, "stack" points to the PRFileDesc on the top of the stack. - ** "layer" points to a new FD that is to be inserted into the stack. - ** If layer is being pushed onto the top of the stack, then - ** PR_PushIOLayer switches the contents of stack and layer, and then - ** puts stack on top of layer, so that after it is done, the top of - ** stack is the same "stack" as it was before, and layer is now the - ** FD for the former top of stack. - ** After this call, stack always points to the top PRFD on the stack. - ** If this function fails, the contents of stack and layer are as - ** they were before the call. - */ - status = PR_PushIOLayer(stack, id, layer); - if (status != PR_SUCCESS) - goto loser; - - ns->fd = (id == PR_TOP_IO_LAYER) ? stack : layer; - return PR_SUCCESS; - -loser: - if (layer) { - layer->dtor(layer); /* free layer */ - } - return PR_FAILURE; -} - -/* if this fails, caller must destroy socket. */ -static SECStatus -ssl_MakeLocks(sslSocket *ss) -{ - ss->firstHandshakeLock = PZ_NewMonitor(nssILockSSL); - if (!ss->firstHandshakeLock) - goto loser; - ss->ssl3HandshakeLock = PZ_NewMonitor(nssILockSSL); - if (!ss->ssl3HandshakeLock) - goto loser; - ss->specLock = NSSRWLock_New(SSL_LOCK_RANK_SPEC, NULL); - if (!ss->specLock) - goto loser; - ss->recvBufLock = PZ_NewMonitor(nssILockSSL); - if (!ss->recvBufLock) - goto loser; - ss->xmitBufLock = PZ_NewMonitor(nssILockSSL); - if (!ss->xmitBufLock) - goto loser; - ss->writerThread = NULL; - if (ssl_lock_readers) { - ss->recvLock = PZ_NewLock(nssILockSSL); - if (!ss->recvLock) - goto loser; - ss->sendLock = PZ_NewLock(nssILockSSL); - if (!ss->sendLock) - goto loser; - } - return SECSuccess; -loser: - ssl_DestroyLocks(ss); - return SECFailure; -} - -#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) -#define NSS_HAVE_GETENV 1 -#endif - -#define LOWER(x) (x | 0x20) /* cheap ToLower function ignores LOCALE */ - -static void -ssl_SetDefaultsFromEnvironment(void) -{ -#if defined(NSS_HAVE_GETENV) - static int firsttime = 1; - - if (firsttime) { - char *ev; - firsttime = 0; -#ifdef DEBUG - ev = PR_GetEnvSecure("SSLDEBUGFILE"); - if (ev && ev[0]) { - ssl_trace_iob = fopen(ev, "w"); - } - if (!ssl_trace_iob) { - ssl_trace_iob = stderr; - } -#ifdef TRACE - ev = PR_GetEnvSecure("SSLTRACE"); - if (ev && ev[0]) { - ssl_trace = atoi(ev); - SSL_TRACE(("SSL: tracing set to %d", ssl_trace)); - } -#endif /* TRACE */ - ev = PR_GetEnvSecure("SSLDEBUG"); - if (ev && ev[0]) { - ssl_debug = atoi(ev); - SSL_TRACE(("SSL: debugging set to %d", ssl_debug)); - } -#endif /* DEBUG */ - ev = PR_GetEnvSecure("SSLKEYLOGFILE"); - if (ev && ev[0]) { - ssl_keylog_iob = fopen(ev, "a"); - if (!ssl_keylog_iob) { - SSL_TRACE(("SSL: failed to open key log file")); - } else { - if (ftell(ssl_keylog_iob) == 0) { - fputs("# SSL/TLS secrets log file, generated by NSS\n", - ssl_keylog_iob); - } - SSL_TRACE(("SSL: logging SSL/TLS secrets to %s", ev)); - } - } -#ifndef NO_PKCS11_BYPASS - ev = PR_GetEnvSecure("SSLBYPASS"); - if (ev && ev[0]) { - ssl_defaults.bypassPKCS11 = (ev[0] == '1'); - SSL_TRACE(("SSL: bypass default set to %d", - ssl_defaults.bypassPKCS11)); - } -#endif /* NO_PKCS11_BYPASS */ - ev = PR_GetEnvSecure("SSLFORCELOCKS"); - if (ev && ev[0] == '1') { - ssl_force_locks = PR_TRUE; - ssl_defaults.noLocks = 0; - strcpy(lockStatus + LOCKSTATUS_OFFSET, "FORCED. "); - SSL_TRACE(("SSL: force_locks set to %d", ssl_force_locks)); - } - ev = PR_GetEnvSecure("NSS_SSL_ENABLE_RENEGOTIATION"); - if (ev) { - if (ev[0] == '1' || LOWER(ev[0]) == 'u') - ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_UNRESTRICTED; - else if (ev[0] == '0' || LOWER(ev[0]) == 'n') - ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER; - else if (ev[0] == '2' || LOWER(ev[0]) == 'r') - ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN; - else if (ev[0] == '3' || LOWER(ev[0]) == 't') - ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_TRANSITIONAL; - SSL_TRACE(("SSL: enableRenegotiation set to %d", - ssl_defaults.enableRenegotiation)); - } - ev = PR_GetEnvSecure("NSS_SSL_REQUIRE_SAFE_NEGOTIATION"); - if (ev && ev[0] == '1') { - ssl_defaults.requireSafeNegotiation = PR_TRUE; - SSL_TRACE(("SSL: requireSafeNegotiation set to %d", - PR_TRUE)); - } - ev = PR_GetEnvSecure("NSS_SSL_CBC_RANDOM_IV"); - if (ev && ev[0] == '0') { - ssl_defaults.cbcRandomIV = PR_FALSE; - SSL_TRACE(("SSL: cbcRandomIV set to 0")); - } - } -#endif /* NSS_HAVE_GETENV */ -} - -/* -** Create a newsocket structure for a file descriptor. -*/ -static sslSocket * -ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) -{ - sslSocket *ss; - - ssl_SetDefaultsFromEnvironment(); - - if (ssl_force_locks) - makeLocks = PR_TRUE; - - /* Make a new socket and get it ready */ - ss = (sslSocket *)PORT_ZAlloc(sizeof(sslSocket)); - if (ss) { - /* This should be of type SSLKEAType, but CC on IRIX - * complains during the for loop. - */ - int i; - SECStatus status; - - ss->opt = ssl_defaults; - ss->opt.useSocks = PR_FALSE; - ss->opt.noLocks = !makeLocks; - ss->vrange = *VERSIONS_DEFAULTS(protocolVariant); - ss->protocolVariant = protocolVariant; - - ss->peerID = NULL; - ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; - ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; - ss->cTimeout = PR_INTERVAL_NO_TIMEOUT; - ss->cipherSpecs = NULL; - ss->sizeCipherSpecs = 0; /* produced lazily */ - ss->preferredCipher = NULL; - ss->url = NULL; - - for (i = kt_null; i < kt_kea_size; i++) { - sslServerCerts *sc = ss->serverCerts + i; - sc->serverCert = NULL; - sc->serverCertChain = NULL; - sc->serverKeyPair = NULL; - sc->serverKeyBits = 0; - ss->certStatusArray[i] = NULL; - } - ss->requestedCertTypes = NULL; - ss->stepDownKeyPair = NULL; - - ss->dheParams = NULL; - ss->dheKeyPair = NULL; - - ss->dbHandle = CERT_GetDefaultCertDB(); - - /* Provide default implementation of hooks */ - ss->authCertificate = SSL_AuthCertificate; - ss->authCertificateArg = (void *)ss->dbHandle; - ss->sniSocketConfig = NULL; - ss->sniSocketConfigArg = NULL; - ss->getClientAuthData = NULL; - ss->handleBadCert = NULL; - ss->badCertArg = NULL; - ss->pkcs11PinArg = NULL; - ss->ephemeralECDHKeyPair = NULL; - ss->getChannelID = NULL; - ss->getChannelIDArg = NULL; - - ssl_ChooseOps(ss); - ssl2_InitSocketPolicy(ss); - ssl3_InitSocketPolicy(ss); - PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight); - PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares); - - if (makeLocks) { - status = ssl_MakeLocks(ss); - if (status != SECSuccess) - goto loser; - } - status = ssl_CreateSecurityInfo(ss); - if (status != SECSuccess) - goto loser; - status = ssl_InitGather(&ss->gs); - if (status != SECSuccess) { - loser: - ssl_DestroySocketContents(ss); - ssl_DestroyLocks(ss); - PORT_Free(ss); - ss = NULL; - } - } - return ss; -}
diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h deleted file mode 100644 index 6f26e5f..0000000 --- a/net/third_party/nss/ssl/sslt.h +++ /dev/null
@@ -1,269 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file contains prototypes for the public SSL functions. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __sslt_h_ -#define __sslt_h_ - -#include "prtypes.h" - -typedef struct SSL3StatisticsStr { - /* statistics from ssl3_SendClientHello (sch) */ - long sch_sid_cache_hits; - long sch_sid_cache_misses; - long sch_sid_cache_not_ok; - - /* statistics from ssl3_HandleServerHello (hsh) */ - long hsh_sid_cache_hits; - long hsh_sid_cache_misses; - long hsh_sid_cache_not_ok; - - /* statistics from ssl3_HandleClientHello (hch) */ - long hch_sid_cache_hits; - long hch_sid_cache_misses; - long hch_sid_cache_not_ok; - - /* statistics related to stateless resume */ - long sch_sid_stateless_resumes; - long hsh_sid_stateless_resumes; - long hch_sid_stateless_resumes; - long hch_sid_ticket_parse_failures; -} SSL3Statistics; - -/* Key Exchange algorithm values */ -typedef enum { - ssl_kea_null = 0, - ssl_kea_rsa = 1, - ssl_kea_dh = 2, - ssl_kea_fortezza = 3, /* deprecated, now unused */ - ssl_kea_ecdh = 4, - ssl_kea_size /* number of ssl_kea_ algorithms */ -} SSLKEAType; - -/* The following defines are for backwards compatibility. -** They will be removed in a forthcoming release to reduce namespace pollution. -** programs that use the kt_ symbols should convert to the ssl_kt_ symbols -** soon. -*/ -#define kt_null ssl_kea_null -#define kt_rsa ssl_kea_rsa -#define kt_dh ssl_kea_dh -#define kt_fortezza ssl_kea_fortezza /* deprecated, now unused */ -#define kt_ecdh ssl_kea_ecdh -#define kt_kea_size ssl_kea_size - -/* Values of this enum match the SignatureAlgorithm enum from - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -typedef enum { - ssl_sign_null = 0, /* "anonymous" in TLS */ - ssl_sign_rsa = 1, - ssl_sign_dsa = 2, - ssl_sign_ecdsa = 3 -} SSLSignType; - -/* Values of this enum match the HashAlgorithm enum from - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -typedef enum { - /* ssl_hash_none is used internally to mean the pre-1.2 combination of MD5 - * and SHA1. The other values are only used in TLS 1.2. */ - ssl_hash_none = 0, - ssl_hash_md5 = 1, - ssl_hash_sha1 = 2, - ssl_hash_sha224 = 3, - ssl_hash_sha256 = 4, - ssl_hash_sha384 = 5, - ssl_hash_sha512 = 6 -} SSLHashType; - -typedef struct SSLSignatureAndHashAlgStr { - SSLHashType hashAlg; - SSLSignType sigAlg; -} SSLSignatureAndHashAlg; - -typedef enum { - ssl_auth_null = 0, - ssl_auth_rsa = 1, - ssl_auth_dsa = 2, - ssl_auth_kea = 3, - ssl_auth_ecdsa = 4 -} SSLAuthType; - -typedef enum { - ssl_calg_null = 0, - ssl_calg_rc4 = 1, - ssl_calg_rc2 = 2, - ssl_calg_des = 3, - ssl_calg_3des = 4, - ssl_calg_idea = 5, - ssl_calg_fortezza = 6, /* deprecated, now unused */ - ssl_calg_aes = 7, - ssl_calg_camellia = 8, - ssl_calg_seed = 9, - ssl_calg_aes_gcm = 10, - ssl_calg_chacha20 = 11 -} SSLCipherAlgorithm; - -typedef enum { - ssl_mac_null = 0, - ssl_mac_md5 = 1, - ssl_mac_sha = 2, - ssl_hmac_md5 = 3, /* TLS HMAC version of mac_md5 */ - ssl_hmac_sha = 4, /* TLS HMAC version of mac_sha */ - ssl_hmac_sha256 = 5, - ssl_mac_aead = 6 -} SSLMACAlgorithm; - -typedef enum { - ssl_compression_null = 0, - ssl_compression_deflate = 1 /* RFC 3749 */ -} SSLCompressionMethod; - -typedef struct SSLChannelInfoStr { - /* |length| is obsolete. On return, SSL_GetChannelInfo sets |length| to the - * smaller of the |len| argument and the length of the struct. The caller - * may ignore |length|. */ - PRUint32 length; - PRUint16 protocolVersion; - PRUint16 cipherSuite; - - /* server authentication info */ - PRUint32 authKeyBits; - - /* key exchange algorithm info */ - PRUint32 keaKeyBits; - - /* session info */ - PRUint32 creationTime; /* seconds since Jan 1, 1970 */ - PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */ - PRUint32 expirationTime; /* seconds since Jan 1, 1970 */ - PRUint32 sessionIDLength; /* up to 32 */ - PRUint8 sessionID[32]; - - /* The following fields are added in NSS 3.12.5. */ - - /* compression method info */ - const char* compressionMethodName; - SSLCompressionMethod compressionMethod; - - /* The following fields are added in NSS 3.21. - * This field only has meaning in TLS < 1.3 and will be set to - * PR_FALSE in TLS 1.3. - */ - PRBool extendedMasterSecretUsed; -} SSLChannelInfo; - -/* Preliminary channel info */ -#define ssl_preinfo_version (1U << 0) -#define ssl_preinfo_cipher_suite (1U << 1) -#define ssl_preinfo_all (ssl_preinfo_version | ssl_preinfo_cipher_suite) - -typedef struct SSLPreliminaryChannelInfoStr { - /* |length| is obsolete. On return, SSL_GetPreliminaryChannelInfo sets - * |length| to the smaller of the |len| argument and the length of the - * struct. The caller may ignore |length|. */ - PRUint32 length; - /* A bitfield over SSLPreliminaryValueSet that describes which - * preliminary values are set (see ssl_preinfo_*). */ - PRUint32 valuesSet; - /* Protocol version: test (valuesSet & ssl_preinfo_version) */ - PRUint16 protocolVersion; - /* Cipher suite: test (valuesSet & ssl_preinfo_cipher_suite) */ - PRUint16 cipherSuite; -} SSLPreliminaryChannelInfo; - -typedef struct SSLCipherSuiteInfoStr { - /* |length| is obsolete. On return, SSL_GetCipherSuitelInfo sets |length| - * to the smaller of the |len| argument and the length of the struct. The - * caller may ignore |length|. */ - PRUint16 length; - PRUint16 cipherSuite; - - /* Cipher Suite Name */ - const char* cipherSuiteName; - - /* server authentication info */ - const char* authAlgorithmName; - SSLAuthType authAlgorithm; - - /* key exchange algorithm info */ - const char* keaTypeName; - SSLKEAType keaType; - - /* symmetric encryption info */ - const char* symCipherName; - SSLCipherAlgorithm symCipher; - PRUint16 symKeyBits; - PRUint16 symKeySpace; - PRUint16 effectiveKeyBits; - - /* MAC info */ - /* AEAD ciphers don't have a MAC. For an AEAD cipher, macAlgorithmName - * is "AEAD", macAlgorithm is ssl_mac_aead, and macBits is the length in - * bits of the authentication tag. */ - const char* macAlgorithmName; - SSLMACAlgorithm macAlgorithm; - PRUint16 macBits; - - PRUintn isFIPS : 1; - PRUintn isExportable : 1; - PRUintn nonStandard : 1; - PRUintn reservedBits : 29; - -} SSLCipherSuiteInfo; - -typedef enum { - ssl_variant_stream = 0, - ssl_variant_datagram = 1 -} SSLProtocolVariant; - -typedef struct SSLVersionRangeStr { - PRUint16 min; - PRUint16 max; -} SSLVersionRange; - -typedef enum { - SSL_sni_host_name = 0, - SSL_sni_type_total -} SSLSniNameType; - -/* Supported extensions. */ -/* Update SSL_MAX_EXTENSIONS whenever a new extension type is added. */ -typedef enum { - ssl_server_name_xtn = 0, - ssl_cert_status_xtn = 5, -#ifndef NSS_DISABLE_ECC - ssl_elliptic_curves_xtn = 10, - ssl_ec_point_formats_xtn = 11, -#endif - ssl_signature_algorithms_xtn = 13, - ssl_use_srtp_xtn = 14, - ssl_app_layer_protocol_xtn = 16, - /* signed_certificate_timestamp extension, RFC 6962 */ - ssl_signed_cert_timestamp_xtn = 18, - ssl_padding_xtn = 21, - ssl_extended_master_secret_xtn = 23, - ssl_session_ticket_xtn = 35, - ssl_tls13_key_share_xtn = 40, /* unofficial TODO(ekr) */ - ssl_next_proto_nego_xtn = 13172, - ssl_channel_id_xtn = 30032, - ssl_renegotiation_info_xtn = 0xff01, - ssl_tls13_draft_version_xtn = 0xff02 /* experimental number */ -} SSLExtensionType; - -#define SSL_MAX_EXTENSIONS 15 /* doesn't include ssl_padding_xtn. */ - -typedef enum { - ssl_dhe_group_none = 0, - ssl_ff_dhe_2048_group = 1, - ssl_ff_dhe_3072_group = 2, - ssl_ff_dhe_4096_group = 3, - ssl_ff_dhe_6144_group = 4, - ssl_ff_dhe_8192_group = 5, - ssl_dhe_group_max -} SSLDHEGroupType; - -#endif /* __sslt_h_ */
diff --git a/net/third_party/nss/ssl/ssltrace.c b/net/third_party/nss/ssl/ssltrace.c deleted file mode 100644 index 6be9a6d..0000000 --- a/net/third_party/nss/ssl/ssltrace.c +++ /dev/null
@@ -1,238 +0,0 @@ -/* - * Functions to trace SSL protocol behavior in DEBUG builds. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include <stdarg.h> -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "prprf.h" - -#if defined(DEBUG) || defined(TRACE) -static const char *hex = "0123456789abcdef"; - -static const char printable[257] = { - "................" /* 0x */ - "................" /* 1x */ - " !\"#$%&'()*+,-./" /* 2x */ - "0123456789:;<=>?" /* 3x */ - "@ABCDEFGHIJKLMNO" /* 4x */ - "PQRSTUVWXYZ[\\]^_" /* 5x */ - "`abcdefghijklmno" /* 6x */ - "pqrstuvwxyz{|}~." /* 7x */ - "................" /* 8x */ - "................" /* 9x */ - "................" /* ax */ - "................" /* bx */ - "................" /* cx */ - "................" /* dx */ - "................" /* ex */ - "................" /* fx */ -}; - -void -ssl_PrintBuf(sslSocket *ss, const char *msg, const void *vp, int len) -{ - const unsigned char *cp = (const unsigned char *)vp; - char buf[80]; - char *bp; - char *ap; - - if (ss) { - SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", SSL_GETPID(), ss->fd, - msg, len)); - } else { - SSL_TRACE(("%d: SSL: %s [Len: %d]", SSL_GETPID(), msg, len)); - } - memset(buf, ' ', sizeof buf); - bp = buf; - ap = buf + 50; - while (--len >= 0) { - unsigned char ch = *cp++; - *bp++ = hex[(ch >> 4) & 0xf]; - *bp++ = hex[ch & 0xf]; - *bp++ = ' '; - *ap++ = printable[ch]; - if (ap - buf >= 66) { - *ap = 0; - SSL_TRACE((" %s", buf)); - memset(buf, ' ', sizeof buf); - bp = buf; - ap = buf + 50; - } - } - if (bp > buf) { - *ap = 0; - SSL_TRACE((" %s", buf)); - } -} - -#define LEN(cp) (((cp)[0] << 8) | ((cp)[1])) - -static void -PrintType(sslSocket *ss, char *msg) -{ - if (ss) { - SSL_TRACE(("%d: SSL[%d]: dump-msg: %s", SSL_GETPID(), ss->fd, msg)); - } else { - SSL_TRACE(("%d: SSL: dump-msg: %s", SSL_GETPID(), msg)); - } -} - -static void -PrintInt(sslSocket *ss, char *msg, unsigned v) -{ - if (ss) { - SSL_TRACE(("%d: SSL[%d]: %s=%u", SSL_GETPID(), ss->fd, msg, v)); - } else { - SSL_TRACE(("%d: SSL: %s=%u", SSL_GETPID(), msg, v)); - } -} - -/* PrintBuf is just like ssl_PrintBuf above, except that: - * a) It prefixes each line of the buffer with "XX: SSL[xxx] " - * b) It dumps only hex, not ASCII. - */ -static void -PrintBuf(sslSocket *ss, char *msg, unsigned char *cp, int len) -{ - char buf[80]; - char *bp; - - if (ss) { - SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", - SSL_GETPID(), ss->fd, msg, len)); - } else { - SSL_TRACE(("%d: SSL: %s [Len: %d]", - SSL_GETPID(), msg, len)); - } - bp = buf; - while (--len >= 0) { - unsigned char ch = *cp++; - *bp++ = hex[(ch >> 4) & 0xf]; - *bp++ = hex[ch & 0xf]; - *bp++ = ' '; - if (bp + 4 > buf + 50) { - *bp = 0; - if (ss) { - SSL_TRACE(("%d: SSL[%d]: %s", - SSL_GETPID(), ss->fd, buf)); - } else { - SSL_TRACE(("%d: SSL: %s", SSL_GETPID(), buf)); - } - bp = buf; - } - } - if (bp > buf) { - *bp = 0; - if (ss) { - SSL_TRACE(("%d: SSL[%d]: %s", - SSL_GETPID(), ss->fd, buf)); - } else { - SSL_TRACE(("%d: SSL: %s", SSL_GETPID(), buf)); - } - } -} - -void -ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len) -{ - switch (bp[0]) { - case SSL_MT_ERROR: - PrintType(ss, "Error"); - PrintInt(ss, "error", LEN(bp + 1)); - break; - - case SSL_MT_CLIENT_HELLO: { - unsigned lcs = LEN(bp + 3); - unsigned ls = LEN(bp + 5); - unsigned lc = LEN(bp + 7); - - PrintType(ss, "Client-Hello"); - - PrintInt(ss, "version (Major)", bp[1]); - PrintInt(ss, "version (minor)", bp[2]); - - PrintBuf(ss, "cipher-specs", bp + 9, lcs); - PrintBuf(ss, "session-id", bp + 9 + lcs, ls); - PrintBuf(ss, "challenge", bp + 9 + lcs + ls, lc); - } break; - case SSL_MT_CLIENT_MASTER_KEY: { - unsigned lck = LEN(bp + 4); - unsigned lek = LEN(bp + 6); - unsigned lka = LEN(bp + 8); - - PrintType(ss, "Client-Master-Key"); - - PrintInt(ss, "cipher-choice", bp[1]); - PrintInt(ss, "key-length", LEN(bp + 2)); - - PrintBuf(ss, "clear-key", bp + 10, lck); - PrintBuf(ss, "encrypted-key", bp + 10 + lck, lek); - PrintBuf(ss, "key-arg", bp + 10 + lck + lek, lka); - } break; - case SSL_MT_CLIENT_FINISHED: - PrintType(ss, "Client-Finished"); - PrintBuf(ss, "connection-id", bp + 1, len - 1); - break; - case SSL_MT_SERVER_HELLO: { - unsigned lc = LEN(bp + 5); - unsigned lcs = LEN(bp + 7); - unsigned lci = LEN(bp + 9); - - PrintType(ss, "Server-Hello"); - - PrintInt(ss, "session-id-hit", bp[1]); - PrintInt(ss, "certificate-type", bp[2]); - PrintInt(ss, "version (Major)", bp[3]); - PrintInt(ss, "version (minor)", bp[3]); - PrintBuf(ss, "certificate", bp + 11, lc); - PrintBuf(ss, "cipher-specs", bp + 11 + lc, lcs); - PrintBuf(ss, "connection-id", bp + 11 + lc + lcs, lci); - } break; - case SSL_MT_SERVER_VERIFY: - PrintType(ss, "Server-Verify"); - PrintBuf(ss, "challenge", bp + 1, len - 1); - break; - case SSL_MT_SERVER_FINISHED: - PrintType(ss, "Server-Finished"); - PrintBuf(ss, "session-id", bp + 1, len - 1); - break; - case SSL_MT_REQUEST_CERTIFICATE: - PrintType(ss, "Request-Certificate"); - PrintInt(ss, "authentication-type", bp[1]); - PrintBuf(ss, "certificate-challenge", bp + 2, len - 2); - break; - case SSL_MT_CLIENT_CERTIFICATE: { - unsigned lc = LEN(bp + 2); - unsigned lr = LEN(bp + 4); - PrintType(ss, "Client-Certificate"); - PrintInt(ss, "certificate-type", bp[1]); - PrintBuf(ss, "certificate", bp + 6, lc); - PrintBuf(ss, "response", bp + 6 + lc, lr); - } break; - default: - ssl_PrintBuf(ss, "sending *unknown* message type", bp, len); - return; - } -} - -void -ssl_Trace(const char *format, ...) -{ - char buf[2000]; - va_list args; - - if (ssl_trace_iob) { - va_start(args, format); - PR_vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - - fputs(buf, ssl_trace_iob); - fputs("\n", ssl_trace_iob); - } -} -#endif
diff --git a/net/third_party/nss/ssl/sslver.c b/net/third_party/nss/ssl/sslver.c deleted file mode 100644 index 666e259..0000000 --- a/net/third_party/nss/ssl/sslver.c +++ /dev/null
@@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Library identity and versioning */ - -#include "nss.h" - -#if defined(DEBUG) -#define _DEBUG_STRING " (debug)" -#else -#define _DEBUG_STRING "" -#endif - -/* - * Version information - */ -const char __nss_ssl_version[] = "Version: NSS " NSS_VERSION _DEBUG_STRING;
diff --git a/net/third_party/nss/ssl/tls13con.c b/net/third_party/nss/ssl/tls13con.c deleted file mode 100644 index 4bb136a..0000000 --- a/net/third_party/nss/ssl/tls13con.c +++ /dev/null
@@ -1,2059 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * TLS 1.3 Protocol - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "stdarg.h" -#include "cert.h" -#include "ssl.h" -#include "keyhi.h" -#include "pk11func.h" -#include "secitem.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "sslerr.h" -#include "tls13hkdf.h" -#include "tls13con.h" - -typedef enum { - TrafficKeyEarlyData, - TrafficKeyHandshake, - TrafficKeyApplicationData -} TrafficKeyType; - -typedef enum { - InstallCipherSpecRead, - InstallCipherSpecWrite, - InstallCipherSpecBoth -} InstallCipherSpecDirection; - -#define MAX_FINISHED_SIZE 64 - -static SECStatus tls13_InitializeHandshakeEncryption(sslSocket *ss); -static SECStatus tls13_InstallCipherSpec( - sslSocket *ss, InstallCipherSpecDirection direction); -static SECStatus tls13_InitCipherSpec( - sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install); -static SECStatus tls13_AESGCM( - ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, int *outlen, int maxout, - const unsigned char *in, int inlen, - const unsigned char *additionalData, int additionalDataLen); -static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss); -static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, - PRUint32 length); -static SECStatus tls13_HandleCertificate( - sslSocket *ss, SSL3Opaque *b, PRUint32 length); -static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, - PRUint32 length); -static SECStatus tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, - PRUint32 length); -static SECStatus tls13_HandleCertificateVerify( - sslSocket *ss, SSL3Opaque *b, PRUint32 length, - SSL3Hashes *hashes); -static SECStatus tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey *key, - SharedSecretType keyType); -static SECStatus tls13_SendFinished(sslSocket *ss); -static SECStatus tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, - const SSL3Hashes *hashes); -static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, - PRUint32 length); -static SECStatus tls13_ComputeSecrets1(sslSocket *ss); -static SECStatus tls13_ComputeFinished( - sslSocket *ss, const SSL3Hashes *hashes, - PRBool sending, - PRUint8 *output, unsigned int *outputLen, - unsigned int maxOutputLen); -static SECStatus tls13_SendClientSecondRound(sslSocket *ss); -static SECStatus tls13_FinishHandshake(sslSocket *ss); - -const char kHkdfLabelExpandedSs[] = "expanded static secret"; -const char kHkdfLabelExpandedEs[] = "expanded ephemeral secret"; -const char kHkdfLabelMasterSecret[] = "master secret"; -const char kHkdfLabelTrafficSecret[] = "traffic secret"; -const char kHkdfLabelClientFinishedSecret[] = "client finished"; -const char kHkdfLabelServerFinishedSecret[] = "server finished"; -const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret"; -const char kHkdfLabelExporterMasterSecret[] = "exporter master secret"; -const char kHkdfPhaseEarlyHandshakeDataKeys[] = "early handshake key expansion"; -const char kHkdfPhaseEarlyApplicationDataKeys[] = "early application data key expansion"; -const char kHkdfPhaseHandshakeKeys[] = "handshake key expansion"; -const char kHkdfPhaseApplicationDataKeys[] = "application data key expansion"; -const char kHkdfPurposeClientWriteKey[] = "client write key"; -const char kHkdfPurposeServerWriteKey[] = "server write key"; -const char kHkdfPurposeClientWriteIv[] = "client write iv"; -const char kHkdfPurposeServerWriteIv[] = "server write iv"; -const char kClientFinishedLabel[] = "client finished"; -const char kServerFinishedLabel[] = "server finished"; - -const SSL3ProtocolVersion kRecordVersion = 0x0301U; - -#define FATAL_ERROR(ss, prError, desc) \ - do { \ - SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \ - SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \ - tls13_FatalError(ss, prError, desc); \ - } while (0) - -#define UNIMPLEMENTED() \ - do { \ - SSL_TRC(3, ("%d: TLS13[%d]: unimplemented feature in %s (%s:%d)", \ - SSL_GETPID(), ss->fd, __func__, __FILE__, __LINE__)); \ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); \ - PORT_Assert(0); \ - return SECFailure; \ - } while (0) - -void -tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc) -{ - PORT_Assert(desc != internal_error); /* These should never happen */ - (void)SSL3_SendAlert(ss, alert_fatal, desc); - PORT_SetError(prError); -} - -#ifdef TRACE -#define STATE_CASE(a) \ - case a: \ - return #a -static char * -tls13_HandshakeState(SSL3WaitState st) -{ - switch (st) { - STATE_CASE(wait_client_hello); - STATE_CASE(wait_client_cert); - STATE_CASE(wait_cert_verify); - STATE_CASE(wait_finished); - STATE_CASE(wait_server_hello); - STATE_CASE(wait_certificate_status); - STATE_CASE(wait_server_cert); - STATE_CASE(wait_cert_request); - STATE_CASE(wait_encrypted_extensions); - STATE_CASE(idle_handshake); - default: - break; - } - PORT_Assert(0); - return "unknown"; -} -#endif - -#define TLS13_WAIT_STATE_MASK 0x80 - -#define TLS13_BASE_WAIT_STATE(ws) (ws & ~TLS13_WAIT_STATE_MASK) -/* We don't mask idle_handshake because other parts of the code use it*/ -#define TLS13_WAIT_STATE(ws) (ws == idle_handshake ? ws : ws | TLS13_WAIT_STATE_MASK) -#define TLS13_CHECK_HS_STATE(ss, err, ...) \ - tls13_CheckHsState(ss, err, #err, __func__, __FILE__, __LINE__, \ - __VA_ARGS__, \ - wait_invalid) -void -tls13_SetHsState(sslSocket *ss, SSL3WaitState ws, - const char *func, const char *file, int line) -{ -#ifdef TRACE - const char *new_state_name = - tls13_HandshakeState(ws); - - SSL_TRC(3, ("%d: TLS13[%d]: state change from %s->%s in %s (%s:%d)", - SSL_GETPID(), ss->fd, - tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)), - new_state_name, - func, file, line)); -#endif - - ss->ssl3.hs.ws = TLS13_WAIT_STATE(ws); -} - -static PRBool -tls13_InHsStateV(sslSocket *ss, va_list ap) -{ - SSL3WaitState ws; - - while ((ws = va_arg(ap, SSL3WaitState)) != wait_invalid) { - if (ws == TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)) { - return PR_TRUE; - } - } - return PR_FALSE; -} - -PRBool -tls13_InHsState(sslSocket *ss, ...) -{ - PRBool found; - va_list ap; - - va_start(ap, ss); - found = tls13_InHsStateV(ss, ap); - va_end(ap); - - return found; -} - -static SECStatus -tls13_CheckHsState(sslSocket *ss, int err, const char *error_name, - const char *func, const char *file, int line, - ...) -{ - va_list ap; - va_start(ap, line); - if (tls13_InHsStateV(ss, ap)) { - va_end(ap); - return SECSuccess; - } - va_end(ap); - - SSL_TRC(3, ("%d: TLS13[%d]: error %s state is (%s) at %s (%s:%d)", - SSL_GETPID(), ss->fd, - error_name, - tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)), - func, file, line)); - tls13_FatalError(ss, err, unexpected_message); - return SECFailure; -} - -SSLHashType -tls13_GetHash(sslSocket *ss) -{ - /* TODO(ekr@rtfm.com): This needs to actually be looked up. */ - return ssl_hash_sha256; -} - -CK_MECHANISM_TYPE -tls13_GetHkdfMechanism(sslSocket *ss) -{ - /* TODO(ekr@rtfm.com): This needs to actually be looked up. */ - return CKM_NSS_HKDF_SHA256; -} - -static CK_MECHANISM_TYPE -tls13_GetHmacMechanism(sslSocket *ss) -{ - /* TODO(ekr@rtfm.com): This needs to actually be looked up. */ - return CKM_SHA256_HMAC; -} - -/* - * Called from ssl3_SendClientHello - */ -SECStatus -tls13_SetupClientHello(sslSocket *ss) -{ - SECStatus rv; - /* TODO(ekr@rtfm.com): Handle multiple curves here. */ - ECName curves_to_try[] = { ec_secp256r1 }; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - PORT_Assert(!ss->ephemeralECDHKeyPair); - - rv = ssl3_CreateECDHEphemeralKeyPair(curves_to_try[0], - &ss->ephemeralECDHKeyPair); - if (rv != SECSuccess) - return rv; - - return SECSuccess; -} - -static SECStatus -tls13_HandleECDHEKeyShare(sslSocket *ss, - TLS13KeyShareEntry *entry, - SECKEYPrivateKey *privKey, - SharedSecretType type) -{ - SECStatus rv; - SECKEYPublicKey *peerKey; - PK11SymKey *shared; - - peerKey = tls13_ImportECDHKeyShare(ss, entry->key_exchange.data, - entry->key_exchange.len, - entry->group); - if (!peerKey) - return SECFailure; /* Error code set already. */ - - /* Compute shared key. */ - shared = tls13_ComputeECDHSharedKey(ss, privKey, peerKey); - SECKEY_DestroyPublicKey(peerKey); - if (!shared) { - return SECFailure; /* Error code set already. */ - } - - /* Extract key. */ - rv = tls13_HkdfExtractSharedKey(ss, shared, type); - PK11_FreeSymKey(shared); - - return rv; -} - -SECStatus -tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b, - PRUint32 length, SSL3Hashes *hashesPtr) -{ - /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */ - switch (ss->ssl3.hs.msg_type) { - case certificate: - return tls13_HandleCertificate(ss, b, length); - - case certificate_status: - return tls13_HandleCertificateStatus(ss, b, length); - - case certificate_request: - return tls13_HandleCertificateRequest(ss, b, length); - - case certificate_verify: - return tls13_HandleCertificateVerify(ss, b, length, hashesPtr); - - case encrypted_extensions: - return tls13_HandleEncryptedExtensions(ss, b, length); - - case new_session_ticket: - return tls13_HandleNewSessionTicket(ss, b, length); - - case finished: - return tls13_HandleFinished(ss, b, length, hashesPtr); - - default: - FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message); - return SECFailure; - } - - PORT_Assert(0); /* Unreached */ - return SECFailure; -} - -/* Called from ssl3_HandleClientHello. - * - * Caller must hold Handshake and RecvBuf locks. - */ -SECStatus -tls13_HandleClientKeyShare(sslSocket *ss) -{ - ECName expectedGroup; - SECStatus rv; - TLS13KeyShareEntry *found = NULL; - PRCList *cur_p; - - SSL_TRC(3, ("%d: TLS13[%d]: handle client_key_share handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - rv = ssl3_SetupPendingCipherSpec(ss); - if (rv != SECSuccess) - return SECFailure; /* Error code set below */ - - /* Figure out what group we expect */ - switch (ss->ssl3.hs.kea_def->exchKeyType) { -#ifndef NSS_DISABLE_ECC - case ssl_kea_ecdh: - expectedGroup = ssl3_GetCurveNameForServerSocket(ss); - if (!expectedGroup) { - FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, - handshake_failure); - return SECFailure; - } - break; -#endif - default: - /* Got an unknown or unsupported Key Exchange Algorithm. - * Can't happen. */ - FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG, - internal_error); - return SECFailure; - } - - /* Now walk through the keys until we find one for our group */ - cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares); - while (cur_p != &ss->ssl3.hs.remoteKeyShares) { - TLS13KeyShareEntry *offer = (TLS13KeyShareEntry *)cur_p; - - if (offer->group == expectedGroup) { - found = offer; - break; - } - cur_p = PR_NEXT_LINK(cur_p); - } - - if (!found) { - /* No acceptable group. In future, we will need to correct the client. - * Currently just generate an error. - * TODO(ekr@rtfm.com): Write code to correct client. - */ - FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure); - return SECFailure; - } - - /* Generate our key */ - rv = ssl3_CreateECDHEphemeralKeyPair(expectedGroup, &ss->ephemeralECDHKeyPair); - if (rv != SECSuccess) - return rv; - - ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; - ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits( - ss->ephemeralECDHKeyPair->pubKey); - - /* Register the sender */ - rv = ssl3_RegisterServerHelloExtensionSender(ss, ssl_tls13_key_share_xtn, - tls13_ServerSendKeyShareXtn); - if (rv != SECSuccess) - return SECFailure; /* Error code set below */ - - rv = tls13_HandleECDHEKeyShare(ss, found, - ss->ephemeralECDHKeyPair->privKey, - EphemeralSharedSecret); - if (rv != SECSuccess) - return SECFailure; /* Error code set below */ - - return SECSuccess; -} - -/* - * [draft-ietf-tls-tls13-11] Section 6.3.3.2 - * - * opaque DistinguishedName<1..2^16-1>; - * - * struct { - * opaque certificate_extension_oid<1..2^8-1>; - * opaque certificate_extension_values<0..2^16-1>; - * } CertificateExtension; - * - * struct { - * opaque certificate_request_context<0..2^8-1>; - * SignatureAndHashAlgorithm - * supported_signature_algorithms<2..2^16-2>; - * DistinguishedName certificate_authorities<0..2^16-1>; - * CertificateExtension certificate_extensions<0..2^16-1>; - * } CertificateRequest; - */ -static SECStatus -tls13_SendCertificateRequest(sslSocket *ss) -{ - SECStatus rv; - int calen; - SECItem *names; - int nnames; - SECItem *name; - int i; - PRUint8 sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2]; - unsigned int sigAlgsLength = 0; - int length; - - SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request", - SSL_GETPID(), ss->fd)); - - /* Fixed context value. */ - ss->ssl3.hs.certReqContext[0] = 0; - ss->ssl3.hs.certReqContextLen = 1; - - rv = ssl3_EncodeCertificateRequestSigAlgs(ss, sigAlgs, sizeof(sigAlgs), - &sigAlgsLength); - if (rv != SECSuccess) { - return rv; - } - - ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames); - length = 1 + ss->ssl3.hs.certReqContextLen + - 2 + sigAlgsLength + 2 + calen + 2; - - rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.certReqContext, - ss->ssl3.hs.certReqContextLen, 1); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - rv = ssl3_AppendHandshakeNumber(ss, calen, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - for (i = 0, name = names; i < nnames; i++, name++) { - rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - } - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - - return SECSuccess; -} - -static SECStatus -tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv; - SECItem context = { siBuffer, NULL, 0 }; - SECItem algorithms = { siBuffer, NULL, 0 }; - PLArenaPool *arena; - CERTDistNames ca_list; - PRInt32 extensionsLength; - - SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - /* Client */ - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, wait_cert_request); - if (rv != SECSuccess) { - return SECFailure; - } - - PORT_Assert(ss->ssl3.clientCertChain == NULL); - PORT_Assert(ss->ssl3.clientCertificate == NULL); - PORT_Assert(ss->ssl3.clientPrivateKey == NULL); - - rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length); - if (rv != SECSuccess) - return SECFailure; - PORT_Assert(sizeof(ss->ssl3.hs.certReqContext) == 255); - PORT_Memcpy(ss->ssl3.hs.certReqContext, context.data, context.len); - ss->ssl3.hs.certReqContextLen = context.len; - - rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &b, &length); - if (rv != SECSuccess) - return SECFailure; - - if (algorithms.len == 0 || (algorithms.len & 1) != 0) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, - illegal_parameter); - return SECFailure; - } - - arena = ca_list.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list); - if (rv != SECSuccess) - goto loser; /* alert sent below */ - - /* Verify that the extensions length is correct. */ - extensionsLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (extensionsLength < 0) { - goto loser; /* alert sent below */ - } - if (extensionsLength != length) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, - illegal_parameter); - goto loser; - } - - TLS13_SET_HS_STATE(ss, wait_server_cert); - - rv = ssl3_CompleteHandleCertificateRequest(ss, &algorithms, &ca_list); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - goto loser; - } - - return SECSuccess; - -loser: - PORT_FreeArena(arena, PR_FALSE); - return SECFailure; -} - -static SECStatus -tls13_InitializeHandshakeEncryption(sslSocket *ss) -{ - SECStatus rv; - - /* For all present cipher suites, SS = ES. - * TODO(ekr@rtfm.com): Revisit for 0-RTT. */ - ss->ssl3.hs.xSS = PK11_ReferenceSymKey(ss->ssl3.hs.xES); - if (!ss->ssl3.hs.xSS) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - rv = tls13_InitCipherSpec(ss, TrafficKeyHandshake, - InstallCipherSpecBoth); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error); - return SECFailure; - } - - return rv; -} - -/* Called from: ssl3_HandleClientHello */ -SECStatus -tls13_SendServerHelloSequence(sslSocket *ss) -{ - SECStatus rv; - SSL3KEAType certIndex; - - SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - rv = ssl3_SendServerHello(ss); - if (rv != SECSuccess) { - return rv; /* err code is set. */ - } - - rv = tls13_InitializeHandshakeEncryption(ss); - if (rv != SECSuccess) { - return SECFailure; /* error code is set. */ - } - - rv = tls13_SendEncryptedExtensions(ss); - if (rv != SECSuccess) { - return SECFailure; /* error code is set. */ - } - - if (ss->opt.requestCertificate) { - rv = tls13_SendCertificateRequest(ss); - if (rv != SECSuccess) { - return SECFailure; /* error code is set. */ - } - } - rv = ssl3_SendCertificate(ss); - if (rv != SECSuccess) { - return SECFailure; /* error code is set. */ - } - rv = ssl3_SendCertificateStatus(ss); - if (rv != SECSuccess) { - return SECFailure; /* error code is set. */ - } - - /* This was copied from: ssl3_SendCertificate. - * TODO(ekr@rtfm.com): Verify that this selection logic is correct. - * Bug 1237514. - */ - if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) || - (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) { - certIndex = kt_rsa; - } else { - certIndex = ss->ssl3.hs.kea_def->exchKeyType; - } - rv = ssl3_SendCertificateVerify(ss, ss->serverCerts[certIndex].SERVERKEY); - if (rv != SECSuccess) { - return rv; /* err code is set. */ - } - - /* Compute the rest of the secrets except for the resumption - * and exporter secret. */ - rv = tls13_ComputeSecrets1(ss); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - rv = tls13_SendFinished(ss); - if (rv != SECSuccess) { - return rv; /* error code is set. */ - } - - TLS13_SET_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert - : wait_finished); - - return SECSuccess; -} - -/* - * Called from ssl3_HandleServerHello. - * - * Caller must hold Handshake and RecvBuf locks. - */ -SECStatus -tls13_HandleServerKeyShare(sslSocket *ss) -{ - SECStatus rv; - ECName expectedGroup; - PRCList *cur_p; - TLS13KeyShareEntry *entry; - - SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - switch (ss->ssl3.hs.kea_def->exchKeyType) { -#ifndef NSS_DISABLE_ECC - case ssl_kea_ecdh: - expectedGroup = ssl3_PubKey2ECName(ss->ephemeralECDHKeyPair->pubKey); - break; -#endif /* NSS_DISABLE_ECC */ - default: - FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG, handshake_failure); - return SECFailure; - } - - /* This list should have one entry. */ - cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares); - if (!cur_p) { - FATAL_ERROR(ss, SSL_ERROR_MISSING_KEY_SHARE, missing_extension); - return SECFailure; - } - PORT_Assert(PR_NEXT_LINK(cur_p) == &ss->ssl3.hs.remoteKeyShares); - - entry = (TLS13KeyShareEntry *)cur_p; - if (entry->group != expectedGroup) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_SHARE, illegal_parameter); - return SECFailure; - } - - rv = tls13_HandleECDHEKeyShare(ss, entry, - ss->ephemeralECDHKeyPair->privKey, - EphemeralSharedSecret); - - ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; - ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits( - ss->ephemeralECDHKeyPair->pubKey); - - if (rv != SECSuccess) - return SECFailure; /* Error code set below */ - - return tls13_InitializeHandshakeEncryption(ss); -} - -/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete - * tls13 Certificate message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -tls13_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv; - SECItem context = { siBuffer, NULL, 0 }; - - SSL_TRC(3, ("%d: TLS13[%d]: handle certificate handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->sec.isServer) { - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE, - wait_client_cert); - } else { - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE, - wait_cert_request, wait_server_cert); - } - if (rv != SECSuccess) - return SECFailure; - - /* Process the context string */ - rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length); - if (rv != SECSuccess) - return SECFailure; - if (!ss->sec.isServer) { - if (context.len) { - /* The server's context string MUST be empty */ - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, - illegal_parameter); - return SECFailure; - } - } else { - if (!context.len || context.len != ss->ssl3.hs.certReqContextLen || - (NSS_SecureMemcmp(ss->ssl3.hs.certReqContext, - context.data, context.len) != 0)) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, - illegal_parameter); - return SECFailure; - } - context.len = 0; /* Belt and suspenders. Zero out the context. */ - } - - return ssl3_CompleteHandleCertificate(ss, b, length); -} - -/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete - * ssl3 CertificateStatus message. - * Caller must hold Handshake and RecvBuf locks. - */ -static SECStatus -tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv; - - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_STATUS, - wait_certificate_status); - if (rv != SECSuccess) - return rv; - - return ssl3_CompleteHandleCertificateStatus(ss, b, length); -} - -/* - * TODO(ekr@rtfm.com): This install logic needs renaming since it's - * what happens at various stages of cipher spec setup. Legacy from ssl3con.c. - */ -int -tls13_InstallCipherSpec(sslSocket *ss, InstallCipherSpecDirection direction) -{ - SSL_TRC(3, ("%d: TLS13[%d]: Installing new cipher specs direction = %s", - SSL_GETPID(), ss->fd, - direction == InstallCipherSpecRead ? "read" : "write")); - - PORT_Assert(!IS_DTLS(ss)); /* TODO(ekr@rtfm.com): Update for DTLS */ - /* TODO(ekr@rtfm.com): Holddown timer for DTLS. */ - ssl_GetSpecWriteLock(ss); /**************************************/ - - /* Flush out any old stuff in the handshake buffers */ - switch (direction) { - case InstallCipherSpecWrite: { - ssl3CipherSpec *pwSpec; - pwSpec = ss->ssl3.pwSpec; - - ss->ssl3.pwSpec = ss->ssl3.cwSpec; - ss->ssl3.cwSpec = pwSpec; - break; - } break; - case InstallCipherSpecRead: { - ssl3CipherSpec *prSpec; - - prSpec = ss->ssl3.prSpec; - ss->ssl3.prSpec = ss->ssl3.crSpec; - ss->ssl3.crSpec = prSpec; - } break; - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - ssl_ReleaseSpecWriteLock(ss); /**************************************/ - return SECFailure; - } - - /* If we are really through with the old cipher prSpec - * (Both the read and write sides have changed) destroy it. - */ - if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE /*freeSrvName*/); - } - ssl_ReleaseSpecWriteLock(ss); /**************************************/ - - return SECSuccess; -} - -/* Add context to the hash functions as described in - [draft-ietf-tls-tls13; Section 4.9.1] */ -SECStatus -tls13_AddContextToHashes(sslSocket *ss, SSL3Hashes *hashes /* IN/OUT */, - SSLHashType algorithm, PRBool sending) -{ - SECStatus rv = SECSuccess; - PK11Context *ctx; - const unsigned char context_padding[] = { - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - }; - const char *client_cert_verify_string = "TLS 1.3, client CertificateVerify"; - const char *server_cert_verify_string = "TLS 1.3, server CertificateVerify"; - const char *context_string = (sending ^ ss->sec.isServer) ? client_cert_verify_string - : server_cert_verify_string; - unsigned int hashlength; - - /* Double check that we are doing SHA-256 for the handshake hash.*/ - PORT_Assert(hashes->hashAlg == ssl_hash_sha256); - if (hashes->hashAlg != ssl_hash_sha256) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - goto loser; - } - PORT_Assert(hashes->len == 32); - - ctx = PK11_CreateDigestContext(ssl3_TLSHashAlgorithmToOID(algorithm)); - if (!ctx) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - PORT_Assert(SECFailure); - PORT_Assert(!SECSuccess); - - rv |= PK11_DigestBegin(ctx); - rv |= PK11_DigestOp(ctx, context_padding, sizeof(context_padding)); - rv |= PK11_DigestOp(ctx, (unsigned char *)context_string, - strlen(context_string) + 1); /* +1 includes the terminating 0 */ - rv |= PK11_DigestOp(ctx, hashes->u.raw, hashes->len); - /* Update the hash in-place */ - rv |= PK11_DigestFinal(ctx, hashes->u.raw, &hashlength, sizeof(hashes->u.raw)); - PK11_DestroyContext(ctx, PR_TRUE); - PRINT_BUF(90, (NULL, "TLS 1.3 hash with context", hashes->u.raw, hashlength)); - - hashes->len = hashlength; - hashes->hashAlg = algorithm; - - if (rv) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; - } - return SECSuccess; - -loser: - return SECFailure; -} - -static SECStatus -tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey *key, - SharedSecretType keyType) -{ - PK11SymKey **destp; - - switch (keyType) { - case EphemeralSharedSecret: - destp = &ss->ssl3.hs.xES; - break; - case StaticSharedSecret: - destp = &ss->ssl3.hs.xSS; - break; - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - PORT_Assert(!*destp); - return tls13_HkdfExtract(NULL, key, tls13_GetHash(ss), destp); -} - -static SECStatus -tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *pwSpec, - TrafficKeyType type) -{ - size_t keySize = pwSpec->cipher_def->key_size; - size_t ivSize = pwSpec->cipher_def->iv_size + - pwSpec->cipher_def->explicit_nonce_size; /* This isn't always going to - * work, but it does for - * AES-GCM */ - CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(pwSpec->cipher_def->calg); - SSL3Hashes hashes; - PK11SymKey *prk = NULL; - const char *phase; - char label[256]; /* Arbitrary buffer large enough to hold the label */ - SECStatus rv; - -#define FORMAT_LABEL(phase_, purpose_) \ - do { \ - PRUint32 n = PR_snprintf(label, sizeof(label), "%s, %s", phase_, purpose_); \ - /* Check for getting close. */ \ - if ((n + 1) >= sizeof(label)) { \ - PORT_Assert(0); \ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); \ - goto loser; \ - } \ - } while (0) -#define EXPAND_TRAFFIC_KEY(purpose_, target_) \ - do { \ - FORMAT_LABEL(phase, purpose_); \ - rv = tls13_HkdfExpandLabel(prk, tls13_GetHash(ss), \ - hashes.u.raw, hashes.len, \ - label, strlen(label), \ - bulkAlgorithm, keySize, &pwSpec->target_); \ - if (rv != SECSuccess) { \ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); \ - PORT_Assert(0); \ - goto loser; \ - } \ - } while (0) - -#define EXPAND_TRAFFIC_IV(purpose_, target_) \ - do { \ - FORMAT_LABEL(phase, purpose_); \ - rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss), \ - hashes.u.raw, hashes.len, \ - label, strlen(label), \ - pwSpec->target_, ivSize); \ - if (rv != SECSuccess) { \ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); \ - PORT_Assert(0); \ - goto loser; \ - } \ - } while (0) - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0); - if (rv != SECSuccess) { - PORT_Assert(0); /* Should never fail */ - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - PRINT_BUF(60, (ss, "Deriving traffic keys. Session hash=", hashes.u.raw, - hashes.len)); - - switch (type) { - case TrafficKeyHandshake: - phase = kHkdfPhaseHandshakeKeys; - prk = ss->ssl3.hs.xES; - break; - case TrafficKeyApplicationData: - phase = kHkdfPhaseApplicationDataKeys; - prk = ss->ssl3.hs.trafficSecret; - break; - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - PORT_Assert(prk != NULL); - - SSL_TRC(3, ("%d: TLS13[%d]: deriving traffic keys phase='%s'", - SSL_GETPID(), ss->fd, phase)); - - EXPAND_TRAFFIC_KEY(kHkdfPurposeClientWriteKey, client.write_key); - EXPAND_TRAFFIC_KEY(kHkdfPurposeServerWriteKey, server.write_key); - EXPAND_TRAFFIC_IV(kHkdfPurposeClientWriteIv, client.write_iv); - EXPAND_TRAFFIC_IV(kHkdfPurposeServerWriteIv, server.write_iv); - - return SECSuccess; - -loser: - return SECFailure; -} - -/* Set up a cipher spec with keys. If install is nonzero, then also install - * it as the current cipher spec for each value in the mask. */ -SECStatus -tls13_InitCipherSpec(sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install) -{ - ssl3CipherSpec *pwSpec; - ssl3CipherSpec *cwSpec; - SECStatus rv; - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (install == InstallCipherSpecWrite || - install == InstallCipherSpecBoth) { - ssl_GetXmitBufLock(ss); - - rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); - ssl_ReleaseXmitBufLock(ss); - if (rv != SECSuccess) { - goto loser; - } - } - - ssl_GetSpecWriteLock(ss); /**************************************/ - - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - pwSpec = ss->ssl3.pwSpec; - cwSpec = ss->ssl3.cwSpec; - - switch (pwSpec->cipher_def->calg) { - case calg_aes_gcm: - pwSpec->aead = tls13_AESGCM; - break; - default: - PORT_Assert(0); - goto loser; - break; - } - - /* Generic behaviors -- common to all crypto methods */ - if (!IS_DTLS(ss)) { - pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0; - } else { - if (cwSpec->epoch == PR_UINT16_MAX) { - /* The problem here is that we have rehandshaked too many - * times (you are not allowed to wrap the epoch). The - * spec says you should be discarding the connection - * and start over, so not much we can do here. */ - rv = SECFailure; - goto loser; - } - /* The sequence number has the high 16 bits as the epoch. */ - pwSpec->epoch = cwSpec->epoch + 1; - pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = - pwSpec->epoch << 16; - - dtls_InitRecvdRecords(&pwSpec->recvdRecords); - } - pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0; - - rv = tls13_DeriveTrafficKeys(ss, pwSpec, type); - if (rv != SECSuccess) { - goto loser; - } - if (install == InstallCipherSpecWrite || - install == InstallCipherSpecBoth) { - rv = tls13_InstallCipherSpec(ss, InstallCipherSpecWrite); - if (rv != SECSuccess) { - goto loser; - } - } - if (install == InstallCipherSpecRead || - install == InstallCipherSpecBoth) { - rv = tls13_InstallCipherSpec(ss, InstallCipherSpecRead); - if (rv != SECSuccess) { - goto loser; - } - } - ssl_ReleaseSpecWriteLock(ss); /**************************************/ - - return SECSuccess; - -loser: - ssl_ReleaseSpecWriteLock(ss); /**************************************/ - PORT_SetError(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE); - return SECFailure; -} - -static SECStatus -tls13_ComputeSecrets1(sslSocket *ss) -{ - SECStatus rv; - PK11SymKey *mSS = NULL; - PK11SymKey *mES = NULL; - PK11SymKey *masterSecret = NULL; - SSL3Hashes hashes; - - rv = ssl3_SetupPendingCipherSpec(ss); - if (rv != SECSuccess) { - return rv; /* error code set below. */ - } - - rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); - if (rv != SECSuccess) { - PORT_Assert(0); /* Should never fail */ - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; - } - - PORT_Assert(ss->ssl3.hs.xSS); - PORT_Assert(ss->ssl3.hs.xES); - - rv = tls13_HkdfExpandLabel(ss->ssl3.hs.xSS, - tls13_GetHash(ss), - hashes.u.raw, hashes.len, - kHkdfLabelExpandedSs, - strlen(kHkdfLabelExpandedSs), - tls13_GetHkdfMechanism(ss), - hashes.len, &mSS); - if (rv != SECSuccess) { - goto loser; - } - - rv = tls13_HkdfExpandLabel(ss->ssl3.hs.xES, - tls13_GetHash(ss), - hashes.u.raw, hashes.len, - kHkdfLabelExpandedEs, - strlen(kHkdfLabelExpandedEs), - tls13_GetHkdfMechanism(ss), - hashes.len, &mES); - if (rv != SECSuccess) { - goto loser; - } - - rv = tls13_HkdfExtract(mSS, mES, - tls13_GetHash(ss), - &masterSecret); - - if (rv != SECSuccess) { - goto loser; - } - - rv = tls13_HkdfExpandLabel(masterSecret, - tls13_GetHash(ss), - hashes.u.raw, hashes.len, - kHkdfLabelTrafficSecret, - strlen(kHkdfLabelTrafficSecret), - tls13_GetHkdfMechanism(ss), - hashes.len, &ss->ssl3.hs.trafficSecret); - if (rv != SECSuccess) { - goto loser; - } - - rv = tls13_HkdfExpandLabel(masterSecret, - tls13_GetHash(ss), - NULL, 0, - kHkdfLabelClientFinishedSecret, - strlen(kHkdfLabelClientFinishedSecret), - tls13_GetHmacMechanism(ss), - hashes.len, &ss->ssl3.hs.clientFinishedSecret); - if (rv != SECSuccess) { - goto loser; - } - - rv = tls13_HkdfExpandLabel(masterSecret, - tls13_GetHash(ss), - NULL, 0, - kHkdfLabelServerFinishedSecret, - strlen(kHkdfLabelServerFinishedSecret), - tls13_GetHmacMechanism(ss), - hashes.len, &ss->ssl3.hs.serverFinishedSecret); - if (rv != SECSuccess) { - goto loser; - } - -loser: - PK11_FreeSymKey(ss->ssl3.hs.xSS); - ss->ssl3.hs.xSS = NULL; - PK11_FreeSymKey(ss->ssl3.hs.xES); - ss->ssl3.hs.xES = NULL; - - if (mSS) { - PK11_FreeSymKey(mSS); - } - if (mES) { - PK11_FreeSymKey(mES); - } - if (masterSecret) { - PK11_FreeSymKey(masterSecret); - } - - return rv; -} - -void -tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *offer) -{ - SECITEM_ZfreeItem(&offer->key_exchange, PR_FALSE); - PORT_ZFree(offer, sizeof(*offer)); -} - -void -tls13_DestroyKeyShares(PRCList *list) -{ - PRCList *cur_p; - - while (!PR_CLIST_IS_EMPTY(list)) { - cur_p = PR_LIST_TAIL(list); - PR_REMOVE_LINK(cur_p); - tls13_DestroyKeyShareEntry((TLS13KeyShareEntry *)cur_p); - } -} - -/* Implement the SSLAEADCipher interface defined in sslimpl.h. - * - * That interface mixes the AD and the sequence number, but in - * TLS 1.3 there is no additional data so this value is just the - * encoded sequence number and we call it |seqNumBuf|. - */ -static SECStatus -tls13_AESGCM(ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen, - const unsigned char *seqNumBuf, - int seqNumLen) -{ - SECItem param; - SECStatus rv = SECFailure; - unsigned char nonce[12]; - size_t i; - unsigned int uOutLen; - CK_GCM_PARAMS gcmParams; - static const int tagSize = 16; - - PORT_Assert(seqNumLen == 8); - - /* draft-ietf-tls-tls13 Section 5.2.2 specifies the following - * nonce algorithm: - * - * The length of the per-record nonce (iv_length) is set to max(8 bytes, - * N_MIN) for the AEAD algorithm (see [RFC5116] Section 4). An AEAD - * algorithm where N_MAX is less than 8 bytes MUST NOT be used with TLS. - * The per-record nonce for the AEAD construction is formed as follows: - * - * 1. The 64-bit record sequence number is padded to the left with - * zeroes to iv_length. - * - * 2. The padded sequence number is XORed with the static - * client_write_iv or server_write_iv, depending on the role. - * - * The resulting quantity (of length iv_length) is used as the per- - * record nonce. - * - * Per RFC 5288: N_MIN = N_MAX = 12 bytes. - * - */ - memcpy(nonce, keys->write_iv, sizeof(nonce)); - for (i = 0; i < 8; ++i) { - nonce[4 + i] ^= seqNumBuf[i]; - } - - param.type = siBuffer; - param.data = (unsigned char *)&gcmParams; - param.len = sizeof(gcmParams); - gcmParams.pIv = nonce; - gcmParams.ulIvLen = sizeof(nonce); - gcmParams.pAAD = NULL; - gcmParams.ulAADLen = 0; - gcmParams.ulTagBits = tagSize * 8; - - if (doDecrypt) { - rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, - maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, - maxout, in, inlen); - } - *outlen = (int)uOutLen; - - return rv; -} - -static SECStatus -tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv; - PRInt32 innerLength; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - SSL_TRC(3, ("%d: TLS13[%d]: handle encrypted extensions", - SSL_GETPID(), ss->fd)); - - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS, - wait_encrypted_extensions); - if (rv != SECSuccess) { - return SECFailure; - } - - innerLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (innerLength < 0) { - return SECFailure; /* Alert already sent. */ - } - if (innerLength != length) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS, - illegal_parameter); - return SECFailure; - } - - rv = ssl3_HandleHelloExtensions(ss, &b, &length, encrypted_extensions); - if (rv != SECSuccess) { - return SECFailure; /* Error code set below */ - } - - TLS13_SET_HS_STATE(ss, wait_cert_request); - return SECSuccess; -} - -static SECStatus -tls13_SendEncryptedExtensions(sslSocket *ss) -{ - SECStatus rv; - PRInt32 extensions_len = 0; - PRInt32 sent_len = 0; - PRUint32 maxBytes = 65535; - - SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - - extensions_len = ssl3_CallHelloExtensionSenders( - ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]); - - rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, - extensions_len + 2); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - sent_len = ssl3_CallHelloExtensionSenders( - ss, PR_TRUE, extensions_len, - &ss->xtnData.encryptedExtensionsSenders[0]); - PORT_Assert(sent_len == extensions_len); - if (sent_len != extensions_len) { - PORT_Assert(sent_len == 0); - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - return SECSuccess; -} - -/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete - * tls13 CertificateVerify message - * Caller must hold Handshake and RecvBuf locks. - */ -SECStatus -tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, - SSL3Hashes *hashes) -{ - SECItem signed_hash = { siBuffer, NULL, 0 }; - SECStatus rv; - SSLSignatureAndHashAlg sigAndHash; - - SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake", - SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY, - wait_cert_verify); - if (rv != SECSuccess) { - return SECFailure; - } - - if (!hashes) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - /* We only support CertificateVerify messages that use the handshake - * hash. - * TODO(ekr@rtfm.com): This should be easy to relax in TLS 1.3 by - * reading the client's hash algorithm first, but there may - * be subtleties so retain the restriction for now. - */ - rv = tls13_AddContextToHashes(ss, hashes, hashes->hashAlg, PR_FALSE); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error); - return SECFailure; - } - - rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, - &sigAndHash); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY); - return SECFailure; - } - - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( - ss, &sigAndHash, ss->sec.peerCert); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decrypt_error); - return SECFailure; - } - - /* We only support CertificateVerify messages that use the handshake - * hash. */ - if (sigAndHash.hashAlg != hashes->hashAlg) { - FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, decrypt_error); - return SECFailure; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY); - return SECFailure; - } - - if (length != 0) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decode_error); - return SECFailure; - } - - rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash, - PR_TRUE, ss->pkcs11PinArg); - if (rv != SECSuccess) { - FATAL_ERROR(ss, PORT_GetError(), decrypt_error); - return SECFailure; - } - - if (!ss->sec.isServer) { - /* Compute the rest of the secrets except for the resumption - * and exporter secret. */ - rv = tls13_ComputeSecrets1(ss); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - } - TLS13_SET_HS_STATE(ss, wait_finished); - - return SECSuccess; -} - -static SECStatus -tls13_ComputeFinished(sslSocket *ss, const SSL3Hashes *hashes, PRBool sending, - PRUint8 *output, unsigned int *outputLen, unsigned int maxOutputLen) -{ - SECStatus rv; - PK11Context *hmacCtx = NULL; - CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanism(ss); - SECItem param = { siBuffer, NULL, 0 }; - unsigned int outputLenUint; - PK11SymKey *secret = (ss->sec.isServer ^ sending) ? ss->ssl3.hs.clientFinishedSecret - : ss->ssl3.hs.serverFinishedSecret; - - PORT_Assert(secret); - PRINT_BUF(90, (NULL, "Handshake hash", hashes->u.raw, hashes->len)); - - hmacCtx = PK11_CreateContextBySymKey(macAlg, CKA_SIGN, - secret, ¶m); - if (!hmacCtx) { - goto abort; - } - - rv = PK11_DigestBegin(hmacCtx); - if (rv != SECSuccess) - goto abort; - - rv = PK11_DigestOp(hmacCtx, hashes->u.raw, hashes->len); - if (rv != SECSuccess) - goto abort; - - PORT_Assert(maxOutputLen >= hashes->len); - rv = PK11_DigestFinal(hmacCtx, output, &outputLenUint, maxOutputLen); - if (rv != SECSuccess) - goto abort; - *outputLen = outputLenUint; - - PK11_DestroyContext(hmacCtx, PR_TRUE); - return SECSuccess; - -abort: - if (hmacCtx) { - PK11_DestroyContext(hmacCtx, PR_TRUE); - } - - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; -} - -static SECStatus -tls13_SendFinished(sslSocket *ss) -{ - SECStatus rv; - PRUint8 finishedBuf[MAX_FINISHED_SIZE]; - unsigned int finishedLen; - SSL3Hashes hashes; - int errCode; - - SSL_TRC(3, ("%d: TLS13[%d]: send finished handshake", SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - ssl_GetSpecReadLock(ss); - rv = tls13_ComputeFinished(ss, &hashes, PR_TRUE, - finishedBuf, &finishedLen, sizeof(finishedBuf)); - ssl_ReleaseSpecReadLock(ss); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen); - if (rv != SECSuccess) { - errCode = PR_GetError(); - goto alert_loser; - } - - rv = ssl3_AppendHandshake(ss, finishedBuf, finishedLen); - if (rv != SECSuccess) { - errCode = PR_GetError(); - goto alert_loser; - } - - rv = ssl3_FlushHandshake(ss, 0); - if (rv != SECSuccess) { - errCode = PR_GetError(); - goto alert_loser; - } - - if (ss->sec.isServer) { - rv = tls13_InitCipherSpec(ss, TrafficKeyApplicationData, - InstallCipherSpecWrite); - } else { - rv = tls13_InstallCipherSpec(ss, InstallCipherSpecWrite); - } - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - /* TODO(ekr@rtfm.com): Record key log */ - return SECSuccess; - -alert_loser: - (void)SSL3_SendAlert(ss, alert_fatal, internal_error); - PORT_SetError(errCode); /* Restore error code */ - return rv; -} - -static SECStatus -tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, - const SSL3Hashes *hashes) -{ - SECStatus rv; - PRUint8 finishedBuf[MAX_FINISHED_SIZE]; - unsigned int finishedLen; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - SSL_TRC(3, ("%d: TLS13[%d]: handle finished handshake", - SSL_GETPID(), ss->fd)); - - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished); - if (rv != SECSuccess) { - return SECFailure; - } - if (!hashes) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - ssl_GetSpecReadLock(ss); - rv = tls13_ComputeFinished(ss, hashes, PR_FALSE, - finishedBuf, &finishedLen, sizeof(finishedBuf)); - ssl_ReleaseSpecReadLock(ss); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - if (length != finishedLen) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_FINISHED, decode_error); - return SECFailure; - } - - if (NSS_SecureMemcmp(b, finishedBuf, finishedLen) != 0) { - FATAL_ERROR(ss, SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE, - decrypt_error); - return SECFailure; - } - - /* Server is now finished. - * Client sends second flight - */ - /* TODO(ekr@rtfm.com): Send NewSession Ticket if server. */ - if (ss->sec.isServer) { - rv = tls13_InstallCipherSpec(ss, InstallCipherSpecRead); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - rv = tls13_FinishHandshake(ss); - } else { - if (ss->ssl3.hs.authCertificatePending) { - /* TODO(ekr@rtfm.com): Handle pending auth */ - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - PORT_Assert(0); - return SECFailure; - } - rv = tls13_InitCipherSpec(ss, TrafficKeyApplicationData, - InstallCipherSpecRead); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - - rv = tls13_SendClientSecondRound(ss); - if (rv != SECSuccess) - return SECFailure; /* Error code and alerts handled below */ - } - - return rv; -} - -static SECStatus -tls13_FinishHandshake(sslSocket *ss) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.hs.restartTarget == NULL); - - /* The first handshake is now completed. */ - ss->handshake = NULL; - - TLS13_SET_HS_STATE(ss, idle_handshake); - - ssl_FinishHandshake(ss); - - return SECSuccess; -} - -static SECStatus -tls13_SendClientSecondRound(sslSocket *ss) -{ - SECStatus rv; - PRBool sendClientCert; - - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - sendClientCert = !ss->ssl3.sendEmptyCert && - ss->ssl3.clientCertChain != NULL && - ss->ssl3.clientPrivateKey != NULL; - - /* Defer client authentication sending if we are still - * waiting for server authentication. See the long block - * comment in ssl3_SendClientSecondRound for more detail. - */ - if (ss->ssl3.hs.restartTarget) { - PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget"); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - if (ss->ssl3.hs.authCertificatePending && (sendClientCert || - ss->ssl3.sendEmptyCert)) { - SSL_TRC(3, ("%d: TLS13[%p]: deferring ssl3_SendClientSecondRound because" - " certificate authentication is still pending.", - SSL_GETPID(), ss->fd)); - ss->ssl3.hs.restartTarget = tls13_SendClientSecondRound; - return SECWouldBlock; - } - - ssl_GetXmitBufLock(ss); /*******************************/ - if (ss->ssl3.sendEmptyCert) { - ss->ssl3.sendEmptyCert = PR_FALSE; - rv = ssl3_SendEmptyCertificate(ss); - /* Don't send verify */ - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } - } else if (sendClientCert) { - rv = ssl3_SendCertificate(ss); - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } - } - - if (sendClientCert) { - rv = ssl3_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey); - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - ss->ssl3.clientPrivateKey = NULL; - if (rv != SECSuccess) { - goto loser; /* err is set. */ - } - } - - rv = tls13_SendFinished(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ - } - ssl_ReleaseXmitBufLock(ss); /*******************************/ - - /* The handshake is now finished */ - return tls13_FinishHandshake(ss); - -loser: - ssl_ReleaseXmitBufLock(ss); /*******************************/ - return SECFailure; -} - -static SECStatus -tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) -{ - SECStatus rv; - - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET, - idle_handshake); - if (rv != SECSuccess) { - return SECFailure; - } - - UNIMPLEMENTED(); - - /* Ignore */ - return SECSuccess; -} - -typedef enum { - ExtensionNotUsed, - ExtensionClientOnly, - ExtensionSendClear, - ExtensionSendEncrypted, -} Tls13ExtensionStatus; - -static const struct { - SSLExtensionType ex_value; - Tls13ExtensionStatus status; -} KnownExtensions[] = { - { ssl_server_name_xtn, - ExtensionSendEncrypted }, - { - ssl_cert_status_xtn, - ExtensionNotUsed /* TODO(ekr@rtfm.com): Disabled because broken - in TLS 1.3. */ - /* ExtensionSendEncrypted */ - }, - { ssl_elliptic_curves_xtn, - ExtensionSendClear }, - { ssl_ec_point_formats_xtn, - ExtensionNotUsed }, - { ssl_signature_algorithms_xtn, - ExtensionClientOnly }, - { ssl_use_srtp_xtn, - ExtensionSendEncrypted }, - { ssl_app_layer_protocol_xtn, - ExtensionSendEncrypted }, - { ssl_padding_xtn, - ExtensionNotUsed }, - { ssl_extended_master_secret_xtn, - ExtensionNotUsed }, - { ssl_session_ticket_xtn, - ExtensionClientOnly }, - { ssl_tls13_key_share_xtn, - ExtensionSendClear }, - { ssl_next_proto_nego_xtn, - ExtensionNotUsed }, - { ssl_renegotiation_info_xtn, - ExtensionNotUsed }, - { ssl_tls13_draft_version_xtn, - ExtensionClientOnly } -}; - -PRBool -tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message) -{ - unsigned int i; - - PORT_Assert((message == client_hello) || - (message == server_hello) || - (message == encrypted_extensions)); - - for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) { - if (KnownExtensions[i].ex_value == extension) - break; - } - if (i == PR_ARRAY_SIZE(KnownExtensions)) { - /* We have never heard of this extension which is OK on - * the server but not the client. */ - return message == client_hello; - } - - switch (KnownExtensions[i].status) { - case ExtensionNotUsed: - return PR_FALSE; - case ExtensionClientOnly: - return message == client_hello; - case ExtensionSendClear: - return message == client_hello || - message == server_hello; - case ExtensionSendEncrypted: - return message == client_hello || - message == encrypted_extensions; - } - - PORT_Assert(0); - - /* Not reached */ - return PR_TRUE; -} - -/* Helper function to encode a uint32 into a buffer */ -unsigned char * -tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to) -{ - PRUint32 encoded; - - PORT_Assert(bytes > 0 && bytes <= 4); - - encoded = PR_htonl(value); - memcpy(to, ((unsigned char *)(&encoded)) + (4 - bytes), bytes); - return to + bytes; -} - -/* TLS 1.3 doesn't actually have additional data but the aead function - * signature overloads additional data to carry the record sequence - * number and that's what we put here. The TLS 1.3 AEAD functions - * just use this input as the sequence number and not as additional - * data. */ -static void -tls13_FormatAdditionalData(unsigned char *aad, unsigned int length, - SSL3SequenceNumber seqNum) -{ - unsigned char *ptr = aad; - - PORT_Assert(length == 8); - ptr = tls13_EncodeUintX(seqNum.high, 4, ptr); - ptr = tls13_EncodeUintX(seqNum.low, 4, ptr); - PORT_Assert((ptr - aad) == length); -} - -SECStatus -tls13_ProtectRecord(sslSocket *ss, - SSL3ContentType type, - const SSL3Opaque *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf) -{ - ssl3CipherSpec *cwSpec = ss->ssl3.cwSpec; - const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def; - SECStatus rv; - PRUint16 headerLen; - int cipherBytes = 0; - const int tagLen = cipher_def->tag_size; - - SSL_TRC(3, ("%d: TLS13[%d]: protect record of length %u, seq=0x%0x%0x", - SSL_GETPID(), ss->fd, contentLen, - cwSpec->write_seq_num.high, - cwSpec->write_seq_num.low)); - - headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH; - - if (headerLen + contentLen + 1 + tagLen > wrBuf->space) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - /* Copy the data into the wrBuf. We're going to encrypt in-place - * in the AEAD branch anyway */ - PORT_Memcpy(wrBuf->buf + headerLen, pIn, contentLen); - - if (cipher_def->calg == ssl_calg_null) { - /* Shortcut for plaintext */ - cipherBytes = contentLen; - } else { - unsigned char aad[8]; - PORT_Assert(cipher_def->type == type_aead); - - /* Add the content type at the end. */ - wrBuf->buf[headerLen + contentLen] = type; - - /* Stomp the content type to be application_data */ - type = content_application_data; - - tls13_FormatAdditionalData(aad, sizeof(aad), - cwSpec->write_seq_num); - cipherBytes = contentLen + 1; /* Room for the content type on the end. */ - rv = cwSpec->aead( - ss->sec.isServer ? &cwSpec->server : &cwSpec->client, - PR_FALSE, /* do encrypt */ - wrBuf->buf + headerLen, /* output */ - &cipherBytes, /* out len */ - wrBuf->space - headerLen, /* max out */ - wrBuf->buf + headerLen, contentLen + 1, /* input */ - aad, sizeof(aad)); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - return SECFailure; - } - } - - PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 256); - - wrBuf->len = cipherBytes + headerLen; - wrBuf->buf[0] = type; - - if (IS_DTLS(ss)) { - (void)tls13_EncodeUintX(2, dtls_TLSVersionToDTLSVersion(kRecordVersion), - &wrBuf->buf[1]); - (void)tls13_EncodeUintX(cwSpec->write_seq_num.high, 4, &wrBuf->buf[3]); - (void)tls13_EncodeUintX(cwSpec->write_seq_num.low, 4, &wrBuf->buf[7]); - (void)tls13_EncodeUintX(cipherBytes, 2, &wrBuf->buf[11]); - } else { - (void)tls13_EncodeUintX(kRecordVersion, 2, &wrBuf->buf[1]); - (void)tls13_EncodeUintX(cipherBytes, 2, &wrBuf->buf[3]); - } - ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); - - return SECSuccess; -} - -/* Unprotect a TLS 1.3 record and leave the result in plaintext. - * - * Called by ssl3_HandleRecord. Caller must hold the spec read lock. - * Therefore, we MUST not call SSL3_SendAlert(). - * - * If SECFailure is returned, we: - * 1. Set |*alert| to the alert to be sent. - * 2. Call PORT_SetError() witn an appropriate code. - */ -SECStatus -tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, - SSL3AlertDescription *alert) -{ - ssl3CipherSpec *crSpec = ss->ssl3.crSpec; - const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def; - unsigned char aad[8]; - SECStatus rv; - - *alert = bad_record_mac; /* Default alert for most issues. */ - - SSL_TRC(3, ("%d: TLS13[%d]: unprotect record of length %u", - SSL_GETPID(), ss->fd, cText->buf->len)); - - /* We can perform this test in variable time because the record's total - * length and the ciphersuite are both public knowledge. */ - if (cText->buf->len < cipher_def->tag_size) { - PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); - return SECFailure; - } - - /* Verify that the content type is right, even though we overwrite it. */ - if (cText->type != content_application_data) { - /* Do we need a better error here? */ - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - return SECFailure; - } - - /* Check the version number in the record */ - if (cText->version != kRecordVersion) { - /* Do we need a better error here? */ - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - return SECFailure; - } - - /* Decrypt */ - PORT_Assert(cipher_def->type == type_aead); - tls13_FormatAdditionalData(aad, sizeof(aad), - IS_DTLS(ss) ? cText->seq_num - : crSpec->read_seq_num); - rv = crSpec->aead( - ss->sec.isServer ? &crSpec->client : &crSpec->server, - PR_TRUE, /* do decrypt */ - plaintext->buf, /* out */ - (int *)&plaintext->len, /* outlen */ - plaintext->space, /* maxout */ - cText->buf->buf, /* in */ - cText->buf->len, /* inlen */ - aad, sizeof(aad)); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - return SECFailure; - } - - /* The record is right-padded with 0s, followed by the true - * content type, so read from the right until we receive a - * nonzero byte. */ - while (plaintext->len > 0 && !(plaintext->buf[plaintext->len - 1])) { - --plaintext->len; - } - - /* Bogus padding. */ - if (plaintext->len < 1) { - /* It's safe to report this specifically because it happened - * after the MAC has been verified. */ - PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING); - return SECFailure; - } - - /* Record the type. */ - cText->type = plaintext->buf[plaintext->len - 1]; - --plaintext->len; - - return SECSuccess; -}
diff --git a/net/third_party/nss/ssl/tls13con.h b/net/third_party/nss/ssl/tls13con.h deleted file mode 100644 index a96d3236..0000000 --- a/net/third_party/nss/ssl/tls13con.h +++ /dev/null
@@ -1,62 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is PRIVATE to SSL. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __tls13con_h_ -#define __tls13con_h_ - -typedef enum { - StaticSharedSecret, - EphemeralSharedSecret -} SharedSecretType; - -SECStatus tls13_UnprotectRecord( - sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, - SSL3AlertDescription *alert); -unsigned char * -tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to); - -#if defined(WIN32) -#define __func__ __FUNCTION__ -#endif - -void tls13_SetHsState(sslSocket *ss, SSL3WaitState ws, - const char *func, const char *file, int line); -#define TLS13_SET_HS_STATE(ss, ws) \ - tls13_SetHsState(ss, ws, __func__, __FILE__, __LINE__) - -/* Return PR_TRUE if the socket is in one of the given states, else return - * PR_FALSE. Only call the macro not the function, because the trailing - * wait_invalid is needed to terminate the argument list. */ -PRBool tls13_InHsState(sslSocket *ss, ...); -#define TLS13_IN_HS_STATE(ss, ...) \ - tls13_InHsState(ss, __VA_ARGS__, wait_invalid) - -SSLHashType tls13_GetHash(sslSocket *ss); -CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss); -void tls13_FatalError(sslSocket *ss, PRErrorCode prError, - SSL3AlertDescription desc); -SECStatus tls13_SetupClientHello(sslSocket *ss); -SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b, - PRUint32 length, - SSL3Hashes *hashesPtr); -SECStatus tls13_HandleClientKeyShare(sslSocket *ss); -SECStatus tls13_SendServerHelloSequence(sslSocket *ss); -SECStatus tls13_HandleServerKeyShare(sslSocket *ss); -SECStatus tls13_AddContextToHashes(sslSocket *ss, - SSL3Hashes *hashes /* IN/OUT */, - SSLHashType algorithm, PRBool sending); -void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry); -void tls13_DestroyKeyShares(PRCList *list); -PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message); -SECStatus tls13_ProtectRecord(sslSocket *ss, - SSL3ContentType type, - const SSL3Opaque *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf); - -#endif /* __tls13con_h_ */
diff --git a/net/third_party/nss/ssl/tls13hkdf.c b/net/third_party/nss/ssl/tls13hkdf.c deleted file mode 100644 index 3dc2d1b..0000000 --- a/net/third_party/nss/ssl/tls13hkdf.c +++ /dev/null
@@ -1,212 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * TLS 1.3 Protocol - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "keyhi.h" -#include "pk11func.h" -#include "secitem.h" -#include "sslt.h" -#include "sslerr.h" - -// TODO(ekr@rtfm.com): Export this separately. -unsigned char *tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to); - -/* This table contains the mapping between TLS hash identifiers and the - * PKCS#11 identifiers */ -static const struct { - SSLHashType hash; - CK_MECHANISM_TYPE pkcs11Mech; - unsigned int hashSize; -} kTlsHkdfInfo[] = { - { ssl_hash_none, 0, 0 }, - { ssl_hash_md5, 0, 0 }, - { ssl_hash_sha1, 0, 0 }, - { ssl_hash_sha224, 0 }, - { ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 }, - { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 }, - { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 } -}; - -SECStatus -tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash, - PK11SymKey **prkp) -{ - CK_NSS_HKDFParams params; - SECItem paramsi; - SECStatus rv; - SECItem *salt; - PK11SymKey *prk; - - params.bExtract = CK_TRUE; - params.bExpand = CK_FALSE; - params.pInfo = NULL; - params.ulInfoLen = 0UL; - - if (ikm1) { - /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary - * but is imposed on us by the present HKDF interface. */ - rv = PK11_ExtractKeyValue(ikm1); - if (rv != SECSuccess) - return rv; - - salt = PK11_GetKeyData(ikm1); - if (!salt) - return SECFailure; - - params.pSalt = salt->data; - params.ulSaltLen = salt->len; - PORT_Assert(salt->len > 0); - } else { - /* Per documentation for CKM_NSS_HKDF_*: - * - * If the optional salt is given, it is used; otherwise, the salt is - * set to a sequence of zeros equal in length to the HMAC output. - */ - params.pSalt = NULL; - params.ulSaltLen = 0UL; - } - paramsi.data = (unsigned char *)¶ms; - paramsi.len = sizeof(params); - - PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech); - PORT_Assert(kTlsHkdfInfo[baseHash].hashSize); - PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash); - prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech, - ¶msi, kTlsHkdfInfo[baseHash].pkcs11Mech, - CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize); - if (!prk) - return SECFailure; - - *prkp = prk; - return SECSuccess; -} - -SECStatus -tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, - const PRUint8 *handshakeHash, unsigned int handshakeHashLen, - const char *label, unsigned int labelLen, - CK_MECHANISM_TYPE algorithm, unsigned int keySize, - PK11SymKey **keyp) -{ - CK_NSS_HKDFParams params; - SECItem paramsi = { siBuffer, NULL, 0 }; - PRUint8 info[100]; - PRUint8 *ptr = info; - unsigned int infoLen; - PK11SymKey *derived; - const char *kLabelPrefix = "TLS 1.3, "; - const unsigned int kLabelPrefixLen = strlen(kLabelPrefix); - - if (handshakeHash) { - PORT_Assert(handshakeHashLen == kTlsHkdfInfo[baseHash].hashSize); - } else { - PORT_Assert(!handshakeHashLen); - } - - /* - * [draft-ietf-tls-tls13-11] Section 7.1: - * - * HKDF-Expand-Label(Secret, Label, HashValue, Length) = - * HKDF-Expand(Secret, HkdfLabel, Length) - * - * Where HkdfLabel is specified as: - * - * struct HkdfLabel { - * uint16 length; - * opaque label<9..255>; - * opaque hash_value<0..255>; - * }; - * - * Where: - * - HkdfLabel.length is Length - * - HkdfLabel.hash_value is HashValue. - * - HkdfLabel.label is "TLS 1.3, " + Label - * - */ - infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen; - if (infoLen > sizeof(info)) { - PORT_Assert(0); - goto abort; - } - - ptr = tls13_EncodeUintX(keySize, 2, ptr); - ptr = tls13_EncodeUintX(labelLen + kLabelPrefixLen, 1, ptr); - PORT_Memcpy(ptr, kLabelPrefix, kLabelPrefixLen); - ptr += kLabelPrefixLen; - PORT_Memcpy(ptr, label, labelLen); - ptr += labelLen; - ptr = tls13_EncodeUintX(handshakeHashLen, 1, ptr); - if (handshakeHash) { - PORT_Memcpy(ptr, handshakeHash, handshakeHashLen); - ptr += handshakeHashLen; - } - PORT_Assert((ptr - info) == infoLen); - - params.bExtract = CK_FALSE; - params.bExpand = CK_TRUE; - params.pInfo = info; - params.ulInfoLen = infoLen; - paramsi.data = (unsigned char *)¶ms; - paramsi.len = sizeof(params); - - derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech, - ¶msi, algorithm, - CKA_DERIVE, keySize, - CKF_SIGN | CKF_VERIFY); - if (!derived) - return SECFailure; - - *keyp = derived; - - return SECSuccess; - -abort: - PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - return SECFailure; -} - -SECStatus -tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash, - const PRUint8 *handshakeHash, unsigned int handshakeHashLen, - const char *label, unsigned int labelLen, - unsigned char *output, unsigned int outputLen) -{ - PK11SymKey *derived = NULL; - SECItem *rawkey; - SECStatus rv; - - rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen, - label, labelLen, - kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen, - &derived); - if (rv != SECSuccess || !derived) { - goto abort; - } - - rv = PK11_ExtractKeyValue(derived); - if (rv != SECSuccess) { - goto abort; - } - - rawkey = PK11_GetKeyData(derived); - if (!rawkey) { - goto abort; - } - - PORT_Assert(rawkey->len == outputLen); - memcpy(output, rawkey->data, outputLen); - PK11_FreeSymKey(derived); - - return SECSuccess; - -abort: - if (derived) { - PK11_FreeSymKey(derived); - } - PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - return SECFailure; -}
diff --git a/net/third_party/nss/ssl/tls13hkdf.h b/net/third_party/nss/ssl/tls13hkdf.h deleted file mode 100644 index 78347a11..0000000 --- a/net/third_party/nss/ssl/tls13hkdf.h +++ /dev/null
@@ -1,38 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is PRIVATE to SSL. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __tls13hkdf_h_ -#define __tls13hkdf_h_ - -#include "keyhi.h" -#include "sslt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SECStatus tls13_HkdfExtract( - PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash, - PK11SymKey **prkp); -SECStatus tls13_HkdfExpandLabelRaw( - PK11SymKey *prk, SSLHashType baseHash, - const PRUint8 *handshakeHash, unsigned int handshakeHashLen, - const char *label, unsigned int labelLen, - unsigned char *output, unsigned int outputLen); -SECStatus tls13_HkdfExpandLabel( - PK11SymKey *prk, SSLHashType baseHash, - const PRUint8 *handshakeHash, unsigned int handshakeHashLen, - const char *label, unsigned int labelLen, - CK_MECHANISM_TYPE algorithm, unsigned int keySize, - PK11SymKey **keyp); - -#ifdef __cplusplus -} -#endif - -#endif
diff --git a/net/third_party/nss/ssl/unix_err.c b/net/third_party/nss/ssl/unix_err.c deleted file mode 100644 index ca0b0507..0000000 --- a/net/third_party/nss/ssl/unix_err.c +++ /dev/null
@@ -1,837 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* - * This file essentially replicates NSPR's source for the functions that - * map system-specific error codes to NSPR error codes. We would use - * NSPR's functions, instead of duplicating them, but they're private. - * As long as SSL's server session cache code must do platform native I/O - * to accomplish its job, and NSPR's error mapping functions remain private, - * this code will continue to need to be replicated. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if 0 -#include "primpl.h" -#else -#define _PR_POLL_AVAILABLE 1 -#include "prerror.h" -#endif - -#if defined(__bsdi__) || defined(NTO) || defined(DARWIN) || defined(BEOS) -#undef _PR_POLL_AVAILABLE -#endif - -#if defined(_PR_POLL_AVAILABLE) -#include <poll.h> -#endif -#include <errno.h> - -/* forward declarations. */ -void nss_MD_unix_map_default_error(int err); - -void -nss_MD_unix_map_opendir_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_closedir_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_readdir_error(int err) -{ - PRErrorCode prError; - - switch (err) { - case ENOENT: - prError = PR_NO_MORE_FILES_ERROR; - break; -#ifdef EOVERFLOW - case EOVERFLOW: - prError = PR_IO_ERROR; - break; -#endif - case EINVAL: - prError = PR_IO_ERROR; - break; - case ENXIO: - prError = PR_IO_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_unlink_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EPERM: - prError = PR_IS_DIRECTORY_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_stat_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_fstat_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_rename_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EEXIST: - prError = PR_DIRECTORY_NOT_EMPTY_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_access_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_mkdir_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_rmdir_error(int err) -{ - PRErrorCode prError; - - switch (err) { - case EEXIST: - prError = PR_DIRECTORY_NOT_EMPTY_ERROR; - break; - case EINVAL: - prError = PR_DIRECTORY_NOT_EMPTY_ERROR; - break; - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_read_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_INVALID_METHOD_ERROR; - break; - case ENXIO: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_write_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_INVALID_METHOD_ERROR; - break; - case ENXIO: - prError = PR_INVALID_METHOD_ERROR; - break; - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_lseek_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_fsync_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - case EINVAL: - prError = PR_INVALID_METHOD_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_close_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_socket_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_socketavailable_error(int err) -{ - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); -} - -void -nss_MD_unix_map_recv_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_recvfrom_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_send_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_sendto_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_writev_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_accept_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ENODEV: - prError = PR_NOT_TCP_SOCKET_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_connect_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EACCES: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; -#if defined(UNIXWARE) || defined(SNI) || defined(NEC) - /* - * On some platforms, if we connect to a port on the local host - * (the loopback address) that no process is listening on, we get - * EIO instead of ECONNREFUSED. - */ - case EIO: - prError = PR_CONNECT_REFUSED_ERROR; - break; -#endif - case ELOOP: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case ENOENT: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case ENXIO: - prError = PR_IO_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_bind_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; - break; - /* - * UNIX domain sockets are not supported in NSPR - */ - case EIO: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case EISDIR: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case ELOOP: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case ENOENT: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case ENOTDIR: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case EROFS: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_listen_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_shutdown_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_socketpair_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_getsockname_error(int err) -{ - PRErrorCode prError; - switch (err) { - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_getpeername_error(int err) -{ - PRErrorCode prError; - - switch (err) { - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_getsockopt_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_BUFFER_OVERFLOW_ERROR; - break; - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_setsockopt_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_BUFFER_OVERFLOW_ERROR; - break; - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_open_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EAGAIN: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case EBUSY: - prError = PR_IO_ERROR; - break; - case ENODEV: - prError = PR_FILE_NOT_FOUND_ERROR; - break; - case ENOMEM: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case ETIMEDOUT: - prError = PR_REMOTE_FILE_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_mmap_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EAGAIN: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case EMFILE: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case ENODEV: - prError = PR_OPERATION_NOT_SUPPORTED_ERROR; - break; - case ENXIO: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_gethostname_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -void -nss_MD_unix_map_select_error(int err) -{ - nss_MD_unix_map_default_error(err); -} - -#ifdef _PR_POLL_AVAILABLE -void -nss_MD_unix_map_poll_error(int err) -{ - PRErrorCode prError; - - switch (err) { - case EAGAIN: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_poll_revents_error(int err) -{ - if (err & POLLNVAL) - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); - else if (err & POLLHUP) - PR_SetError(PR_CONNECT_RESET_ERROR, EPIPE); - else if (err & POLLERR) - PR_SetError(PR_IO_ERROR, EIO); - else - PR_SetError(PR_UNKNOWN_ERROR, err); -} -#endif /* _PR_POLL_AVAILABLE */ - -void -nss_MD_unix_map_flock_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EINVAL: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; - case EWOULDBLOCK: - prError = PR_FILE_IS_LOCKED_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_unix_map_lockf_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EACCES: - prError = PR_FILE_IS_LOCKED_ERROR; - break; - case EDEADLK: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - default: - nss_MD_unix_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -#ifdef HPUX11 -void -nss_MD_hpux_map_sendfile_error(int err) -{ - nss_MD_unix_map_default_error(err); -} -#endif /* HPUX11 */ - -void -nss_MD_unix_map_default_error(int err) -{ - PRErrorCode prError; - switch (err) { - case EACCES: - prError = PR_NO_ACCESS_RIGHTS_ERROR; - break; - case EADDRINUSE: - prError = PR_ADDRESS_IN_USE_ERROR; - break; - case EADDRNOTAVAIL: - prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; - break; - case EAFNOSUPPORT: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case EAGAIN: - prError = PR_WOULD_BLOCK_ERROR; - break; - /* - * On QNX and Neutrino, EALREADY is defined as EBUSY. - */ -#if EALREADY != EBUSY - case EALREADY: - prError = PR_ALREADY_INITIATED_ERROR; - break; -#endif - case EBADF: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; -#ifdef EBADMSG - case EBADMSG: - prError = PR_IO_ERROR; - break; -#endif - case EBUSY: - prError = PR_FILESYSTEM_MOUNTED_ERROR; - break; - case ECONNREFUSED: - prError = PR_CONNECT_REFUSED_ERROR; - break; - case ECONNRESET: - prError = PR_CONNECT_RESET_ERROR; - break; - case EDEADLK: - prError = PR_DEADLOCK_ERROR; - break; -#ifdef EDIRCORRUPTED - case EDIRCORRUPTED: - prError = PR_DIRECTORY_CORRUPTED_ERROR; - break; -#endif -#ifdef EDQUOT - case EDQUOT: - prError = PR_NO_DEVICE_SPACE_ERROR; - break; -#endif - case EEXIST: - prError = PR_FILE_EXISTS_ERROR; - break; - case EFAULT: - prError = PR_ACCESS_FAULT_ERROR; - break; - case EFBIG: - prError = PR_FILE_TOO_BIG_ERROR; - break; - case EINPROGRESS: - prError = PR_IN_PROGRESS_ERROR; - break; - case EINTR: - prError = PR_PENDING_INTERRUPT_ERROR; - break; - case EINVAL: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case EIO: - prError = PR_IO_ERROR; - break; - case EISCONN: - prError = PR_IS_CONNECTED_ERROR; - break; - case EISDIR: - prError = PR_IS_DIRECTORY_ERROR; - break; - case ELOOP: - prError = PR_LOOP_ERROR; - break; - case EMFILE: - prError = PR_PROC_DESC_TABLE_FULL_ERROR; - break; - case EMLINK: - prError = PR_MAX_DIRECTORY_ENTRIES_ERROR; - break; - case EMSGSIZE: - prError = PR_INVALID_ARGUMENT_ERROR; - break; -#ifdef EMULTIHOP - case EMULTIHOP: - prError = PR_REMOTE_FILE_ERROR; - break; -#endif - case ENAMETOOLONG: - prError = PR_NAME_TOO_LONG_ERROR; - break; - case ENETUNREACH: - prError = PR_NETWORK_UNREACHABLE_ERROR; - break; - case ENFILE: - prError = PR_SYS_DESC_TABLE_FULL_ERROR; - break; -#if !defined(SCO) - case ENOBUFS: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; -#endif - case ENODEV: - prError = PR_FILE_NOT_FOUND_ERROR; - break; - case ENOENT: - prError = PR_FILE_NOT_FOUND_ERROR; - break; - case ENOLCK: - prError = PR_FILE_IS_LOCKED_ERROR; - break; -#ifdef ENOLINK - case ENOLINK: - prError = PR_REMOTE_FILE_ERROR; - break; -#endif - case ENOMEM: - prError = PR_OUT_OF_MEMORY_ERROR; - break; - case ENOPROTOOPT: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case ENOSPC: - prError = PR_NO_DEVICE_SPACE_ERROR; - break; -#ifdef ENOSR - case ENOSR: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; -#endif - case ENOTCONN: - prError = PR_NOT_CONNECTED_ERROR; - break; - case ENOTDIR: - prError = PR_NOT_DIRECTORY_ERROR; - break; - case ENOTSOCK: - prError = PR_NOT_SOCKET_ERROR; - break; - case ENXIO: - prError = PR_FILE_NOT_FOUND_ERROR; - break; - case EOPNOTSUPP: - prError = PR_NOT_TCP_SOCKET_ERROR; - break; -#ifdef EOVERFLOW - case EOVERFLOW: - prError = PR_BUFFER_OVERFLOW_ERROR; - break; -#endif - case EPERM: - prError = PR_NO_ACCESS_RIGHTS_ERROR; - break; - case EPIPE: - prError = PR_CONNECT_RESET_ERROR; - break; -#ifdef EPROTO - case EPROTO: - prError = PR_IO_ERROR; - break; -#endif - case EPROTONOSUPPORT: - prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; - break; - case EPROTOTYPE: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case ERANGE: - prError = PR_INVALID_METHOD_ERROR; - break; - case EROFS: - prError = PR_READ_ONLY_FILESYSTEM_ERROR; - break; - case ESPIPE: - prError = PR_INVALID_METHOD_ERROR; - break; - case ETIMEDOUT: - prError = PR_IO_TIMEOUT_ERROR; - break; -#if EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: - prError = PR_WOULD_BLOCK_ERROR; - break; -#endif - case EXDEV: - prError = PR_NOT_SAME_DEVICE_ERROR; - break; - - default: - prError = PR_UNKNOWN_ERROR; - break; - } - PR_SetError(prError, err); -}
diff --git a/net/third_party/nss/ssl/unix_err.h b/net/third_party/nss/ssl/unix_err.h deleted file mode 100644 index 5d7d547..0000000 --- a/net/third_party/nss/ssl/unix_err.h +++ /dev/null
@@ -1,57 +0,0 @@ -/* - * This file essentially replicates NSPR's source for the functions that - * map system-specific error codes to NSPR error codes. We would use - * NSPR's functions, instead of duplicating them, but they're private. - * As long as SSL's server session cache code must do platform native I/O - * to accomplish its job, and NSPR's error mapping functions remain private, - * this code will continue to need to be replicated. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* NSPR doesn't make these functions public, so we have to duplicate -** them in NSS. -*/ -extern void nss_MD_hpux_map_sendfile_error(int err); -extern void nss_MD_unix_map_accept_error(int err); -extern void nss_MD_unix_map_access_error(int err); -extern void nss_MD_unix_map_bind_error(int err); -extern void nss_MD_unix_map_close_error(int err); -extern void nss_MD_unix_map_closedir_error(int err); -extern void nss_MD_unix_map_connect_error(int err); -extern void nss_MD_unix_map_default_error(int err); -extern void nss_MD_unix_map_flock_error(int err); -extern void nss_MD_unix_map_fstat_error(int err); -extern void nss_MD_unix_map_fsync_error(int err); -extern void nss_MD_unix_map_gethostname_error(int err); -extern void nss_MD_unix_map_getpeername_error(int err); -extern void nss_MD_unix_map_getsockname_error(int err); -extern void nss_MD_unix_map_getsockopt_error(int err); -extern void nss_MD_unix_map_listen_error(int err); -extern void nss_MD_unix_map_lockf_error(int err); -extern void nss_MD_unix_map_lseek_error(int err); -extern void nss_MD_unix_map_mkdir_error(int err); -extern void nss_MD_unix_map_mmap_error(int err); -extern void nss_MD_unix_map_open_error(int err); -extern void nss_MD_unix_map_opendir_error(int err); -extern void nss_MD_unix_map_poll_error(int err); -extern void nss_MD_unix_map_poll_revents_error(int err); -extern void nss_MD_unix_map_read_error(int err); -extern void nss_MD_unix_map_readdir_error(int err); -extern void nss_MD_unix_map_recv_error(int err); -extern void nss_MD_unix_map_recvfrom_error(int err); -extern void nss_MD_unix_map_rename_error(int err); -extern void nss_MD_unix_map_rmdir_error(int err); -extern void nss_MD_unix_map_select_error(int err); -extern void nss_MD_unix_map_send_error(int err); -extern void nss_MD_unix_map_sendto_error(int err); -extern void nss_MD_unix_map_setsockopt_error(int err); -extern void nss_MD_unix_map_shutdown_error(int err); -extern void nss_MD_unix_map_socket_error(int err); -extern void nss_MD_unix_map_socketavailable_error(int err); -extern void nss_MD_unix_map_socketpair_error(int err); -extern void nss_MD_unix_map_stat_error(int err); -extern void nss_MD_unix_map_unlink_error(int err); -extern void nss_MD_unix_map_write_error(int err); -extern void nss_MD_unix_map_writev_error(int err);
diff --git a/net/third_party/nss/ssl/win32err.c b/net/third_party/nss/ssl/win32err.c deleted file mode 100644 index caa12b956..0000000 --- a/net/third_party/nss/ssl/win32err.c +++ /dev/null
@@ -1,550 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* - * This file essentially replicates NSPR's source for the functions that - * map system-specific error codes to NSPR error codes. We would use - * NSPR's functions, instead of duplicating them, but they're private. - * As long as SSL's server session cache code must do platform native I/O - * to accomplish its job, and NSPR's error mapping functions remain private, - * this code will continue to need to be replicated. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prerror.h" -#include "prlog.h" -#include <errno.h> -#include <windows.h> - -/* - * On Win32, we map three kinds of error codes: - * - GetLastError(): for Win32 functions - * - WSAGetLastError(): for Winsock functions - * - errno: for standard C library functions - * - * We do not check for WSAEINPROGRESS and WSAEINTR because we do not - * use blocking Winsock 1.1 calls. - * - * Except for the 'socket' call, we do not check for WSAEINITIALISED. - * It is assumed that if Winsock is not initialized, that fact will - * be detected at the time we create new sockets. - */ - -/* forward declaration. */ -void nss_MD_win32_map_default_error(PRInt32 err); - -void -nss_MD_win32_map_opendir_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_closedir_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_readdir_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_delete_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -/* The error code for stat() is in errno. */ -void -nss_MD_win32_map_stat_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_fstat_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_rename_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -/* The error code for access() is in errno. */ -void -nss_MD_win32_map_access_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_mkdir_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_rmdir_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_read_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_transmitfile_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_write_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_lseek_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_fsync_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -/* - * For both CloseHandle() and closesocket(). - */ -void -nss_MD_win32_map_close_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_socket_error(PRInt32 err) -{ - PR_ASSERT(err != WSANOTINITIALISED); - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_recv_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_recvfrom_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_send_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEMSGSIZE: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_sendto_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEMSGSIZE: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_accept_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEOPNOTSUPP: - prError = PR_NOT_TCP_SOCKET_ERROR; - break; - case WSAEINVAL: - prError = PR_INVALID_STATE_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_acceptex_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_connect_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEWOULDBLOCK: - prError = PR_IN_PROGRESS_ERROR; - break; - case WSAEINVAL: - prError = PR_ALREADY_INITIATED_ERROR; - break; - case WSAETIMEDOUT: - prError = PR_IO_TIMEOUT_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_bind_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEINVAL: - prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_listen_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEOPNOTSUPP: - prError = PR_NOT_TCP_SOCKET_ERROR; - break; - case WSAEINVAL: - prError = PR_INVALID_STATE_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_shutdown_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_getsockname_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAEINVAL: - prError = PR_INVALID_STATE_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_getpeername_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_getsockopt_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_setsockopt_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_open_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_gethostname_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -/* Win32 select() only works on sockets. So in this -** context, WSAENOTSOCK is equivalent to EBADF on Unix. -*/ -void -nss_MD_win32_map_select_error(PRInt32 err) -{ - PRErrorCode prError; - switch (err) { - case WSAENOTSOCK: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; - default: - nss_MD_win32_map_default_error(err); - return; - } - PR_SetError(prError, err); -} - -void -nss_MD_win32_map_lockf_error(PRInt32 err) -{ - nss_MD_win32_map_default_error(err); -} - -void -nss_MD_win32_map_default_error(PRInt32 err) -{ - PRErrorCode prError; - - switch (err) { - case EACCES: - prError = PR_NO_ACCESS_RIGHTS_ERROR; - break; - case ENOENT: - prError = PR_FILE_NOT_FOUND_ERROR; - break; - case ERROR_ACCESS_DENIED: - prError = PR_NO_ACCESS_RIGHTS_ERROR; - break; - case ERROR_ALREADY_EXISTS: - prError = PR_FILE_EXISTS_ERROR; - break; - case ERROR_DISK_CORRUPT: - prError = PR_IO_ERROR; - break; - case ERROR_DISK_FULL: - prError = PR_NO_DEVICE_SPACE_ERROR; - break; - case ERROR_DISK_OPERATION_FAILED: - prError = PR_IO_ERROR; - break; - case ERROR_DRIVE_LOCKED: - prError = PR_FILE_IS_LOCKED_ERROR; - break; - case ERROR_FILENAME_EXCED_RANGE: - prError = PR_NAME_TOO_LONG_ERROR; - break; - case ERROR_FILE_CORRUPT: - prError = PR_IO_ERROR; - break; - case ERROR_FILE_EXISTS: - prError = PR_FILE_EXISTS_ERROR; - break; - case ERROR_FILE_INVALID: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; -#if ERROR_FILE_NOT_FOUND != ENOENT - case ERROR_FILE_NOT_FOUND: - prError = PR_FILE_NOT_FOUND_ERROR; - break; -#endif - case ERROR_HANDLE_DISK_FULL: - prError = PR_NO_DEVICE_SPACE_ERROR; - break; - case ERROR_INVALID_ADDRESS: - prError = PR_ACCESS_FAULT_ERROR; - break; - case ERROR_INVALID_HANDLE: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; - case ERROR_INVALID_NAME: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case ERROR_INVALID_PARAMETER: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case ERROR_INVALID_USER_BUFFER: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case ERROR_LOCKED: - prError = PR_FILE_IS_LOCKED_ERROR; - break; - case ERROR_NETNAME_DELETED: - prError = PR_CONNECT_RESET_ERROR; - break; - case ERROR_NOACCESS: - prError = PR_ACCESS_FAULT_ERROR; - break; - case ERROR_NOT_ENOUGH_MEMORY: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case ERROR_NOT_ENOUGH_QUOTA: - prError = PR_OUT_OF_MEMORY_ERROR; - break; - case ERROR_NOT_READY: - prError = PR_IO_ERROR; - break; - case ERROR_NO_MORE_FILES: - prError = PR_NO_MORE_FILES_ERROR; - break; - case ERROR_OPEN_FAILED: - prError = PR_IO_ERROR; - break; - case ERROR_OPEN_FILES: - prError = PR_IO_ERROR; - break; - case ERROR_OUTOFMEMORY: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case ERROR_PATH_BUSY: - prError = PR_IO_ERROR; - break; - case ERROR_PATH_NOT_FOUND: - prError = PR_FILE_NOT_FOUND_ERROR; - break; - case ERROR_SEEK_ON_DEVICE: - prError = PR_IO_ERROR; - break; - case ERROR_SHARING_VIOLATION: - prError = PR_FILE_IS_BUSY_ERROR; - break; - case ERROR_STACK_OVERFLOW: - prError = PR_ACCESS_FAULT_ERROR; - break; - case ERROR_TOO_MANY_OPEN_FILES: - prError = PR_SYS_DESC_TABLE_FULL_ERROR; - break; - case ERROR_WRITE_PROTECT: - prError = PR_NO_ACCESS_RIGHTS_ERROR; - break; - case WSAEACCES: - prError = PR_NO_ACCESS_RIGHTS_ERROR; - break; - case WSAEADDRINUSE: - prError = PR_ADDRESS_IN_USE_ERROR; - break; - case WSAEADDRNOTAVAIL: - prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; - break; - case WSAEAFNOSUPPORT: - prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; - break; - case WSAEALREADY: - prError = PR_ALREADY_INITIATED_ERROR; - break; - case WSAEBADF: - prError = PR_BAD_DESCRIPTOR_ERROR; - break; - case WSAECONNABORTED: - prError = PR_CONNECT_ABORTED_ERROR; - break; - case WSAECONNREFUSED: - prError = PR_CONNECT_REFUSED_ERROR; - break; - case WSAECONNRESET: - prError = PR_CONNECT_RESET_ERROR; - break; - case WSAEDESTADDRREQ: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case WSAEFAULT: - prError = PR_ACCESS_FAULT_ERROR; - break; - case WSAEHOSTUNREACH: - prError = PR_HOST_UNREACHABLE_ERROR; - break; - case WSAEINVAL: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case WSAEISCONN: - prError = PR_IS_CONNECTED_ERROR; - break; - case WSAEMFILE: - prError = PR_PROC_DESC_TABLE_FULL_ERROR; - break; - case WSAEMSGSIZE: - prError = PR_BUFFER_OVERFLOW_ERROR; - break; - case WSAENETDOWN: - prError = PR_NETWORK_DOWN_ERROR; - break; - case WSAENETRESET: - prError = PR_CONNECT_ABORTED_ERROR; - break; - case WSAENETUNREACH: - prError = PR_NETWORK_UNREACHABLE_ERROR; - break; - case WSAENOBUFS: - prError = PR_INSUFFICIENT_RESOURCES_ERROR; - break; - case WSAENOPROTOOPT: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case WSAENOTCONN: - prError = PR_NOT_CONNECTED_ERROR; - break; - case WSAENOTSOCK: - prError = PR_NOT_SOCKET_ERROR; - break; - case WSAEOPNOTSUPP: - prError = PR_OPERATION_NOT_SUPPORTED_ERROR; - break; - case WSAEPROTONOSUPPORT: - prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; - break; - case WSAEPROTOTYPE: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case WSAESHUTDOWN: - prError = PR_SOCKET_SHUTDOWN_ERROR; - break; - case WSAESOCKTNOSUPPORT: - prError = PR_INVALID_ARGUMENT_ERROR; - break; - case WSAETIMEDOUT: - prError = PR_CONNECT_ABORTED_ERROR; - break; - case WSAEWOULDBLOCK: - prError = PR_WOULD_BLOCK_ERROR; - break; - default: - prError = PR_UNKNOWN_ERROR; - break; - } - PR_SetError(prError, err); -}
diff --git a/net/third_party/nss/ssl/win32err.h b/net/third_party/nss/ssl/win32err.h deleted file mode 100644 index a6988490..0000000 --- a/net/third_party/nss/ssl/win32err.h +++ /dev/null
@@ -1,51 +0,0 @@ -/* - * This file essentially replicates NSPR's source for the functions that - * map system-specific error codes to NSPR error codes. We would use - * NSPR's functions, instead of duplicating them, but they're private. - * As long as SSL's server session cache code must do platform native I/O - * to accomplish its job, and NSPR's error mapping functions remain private, - * This code will continue to need to be replicated. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* NSPR doesn't make these functions public, so we have to duplicate -** them in NSS. -*/ -extern void nss_MD_win32_map_accept_error(PRInt32 err); -extern void nss_MD_win32_map_acceptex_error(PRInt32 err); -extern void nss_MD_win32_map_access_error(PRInt32 err); -extern void nss_MD_win32_map_bind_error(PRInt32 err); -extern void nss_MD_win32_map_close_error(PRInt32 err); -extern void nss_MD_win32_map_closedir_error(PRInt32 err); -extern void nss_MD_win32_map_connect_error(PRInt32 err); -extern void nss_MD_win32_map_default_error(PRInt32 err); -extern void nss_MD_win32_map_delete_error(PRInt32 err); -extern void nss_MD_win32_map_fstat_error(PRInt32 err); -extern void nss_MD_win32_map_fsync_error(PRInt32 err); -extern void nss_MD_win32_map_gethostname_error(PRInt32 err); -extern void nss_MD_win32_map_getpeername_error(PRInt32 err); -extern void nss_MD_win32_map_getsockname_error(PRInt32 err); -extern void nss_MD_win32_map_getsockopt_error(PRInt32 err); -extern void nss_MD_win32_map_listen_error(PRInt32 err); -extern void nss_MD_win32_map_lockf_error(PRInt32 err); -extern void nss_MD_win32_map_lseek_error(PRInt32 err); -extern void nss_MD_win32_map_mkdir_error(PRInt32 err); -extern void nss_MD_win32_map_open_error(PRInt32 err); -extern void nss_MD_win32_map_opendir_error(PRInt32 err); -extern void nss_MD_win32_map_read_error(PRInt32 err); -extern void nss_MD_win32_map_readdir_error(PRInt32 err); -extern void nss_MD_win32_map_recv_error(PRInt32 err); -extern void nss_MD_win32_map_recvfrom_error(PRInt32 err); -extern void nss_MD_win32_map_rename_error(PRInt32 err); -extern void nss_MD_win32_map_rmdir_error(PRInt32 err); -extern void nss_MD_win32_map_select_error(PRInt32 err); -extern void nss_MD_win32_map_send_error(PRInt32 err); -extern void nss_MD_win32_map_sendto_error(PRInt32 err); -extern void nss_MD_win32_map_setsockopt_error(PRInt32 err); -extern void nss_MD_win32_map_shutdown_error(PRInt32 err); -extern void nss_MD_win32_map_socket_error(PRInt32 err); -extern void nss_MD_win32_map_stat_error(PRInt32 err); -extern void nss_MD_win32_map_transmitfile_error(PRInt32 err); -extern void nss_MD_win32_map_write_error(PRInt32 err);
diff --git a/net/url_request/url_fetcher_impl_unittest.cc b/net/url_request/url_fetcher_impl_unittest.cc index 1f83e1d..095d6b1c 100644 --- a/net/url_request/url_fetcher_impl_unittest.cc +++ b/net/url_request/url_fetcher_impl_unittest.cc
@@ -45,7 +45,7 @@ #include "net/url_request/url_request_throttler_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) #include "net/cert_net/nss_ocsp.h" #endif @@ -425,14 +425,14 @@ kDefaultResponsePath)); ASSERT_TRUE(hanging_url_.is_valid()); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) crypto::EnsureNSSInit(); EnsureNSSHttpIOInit(); #endif } void TearDown() override { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) ShutdownNSSHttpIO(); #endif }
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index c59ee4f..200349b 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -9235,7 +9235,7 @@ CHECK_NE(static_cast<X509Certificate*>(NULL), root_cert.get()); test_root_.reset(new ScopedTestRoot(root_cert.get())); -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) SetURLRequestContextForNSSHttpIO(&context_); EnsureNSSHttpIOInit(); #endif @@ -9264,7 +9264,7 @@ } ~HTTPSOCSPTest() override { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) ShutdownNSSHttpIO(); #endif } @@ -9304,7 +9304,7 @@ // If it does not, then tests which rely on 'hard fail' behaviour should be // skipped. static bool SystemSupportsHardFailRevocationChecking() { -#if defined(OS_WIN) || defined(USE_NSS_VERIFIER) +#if defined(OS_WIN) || defined(USE_NSS_CERTS) return true; #else return false; @@ -9343,7 +9343,7 @@ } static bool SystemSupportsOCSPStapling() { -#if defined(USE_NSS_VERIFIER) +#if defined(USE_NSS_CERTS) return true; #elif defined(OS_WIN) return base::win::GetVersion() >= base::win::VERSION_VISTA;
diff --git a/remoting/host/token_validator_base.cc b/remoting/host/token_validator_base.cc index 08c077e..99796421 100644 --- a/remoting/host/token_validator_base.cc +++ b/remoting/host/token_validator_base.cc
@@ -151,11 +151,9 @@ client_cert_store = new net::ClientCertStoreWin(cert_store); #elif defined(OS_MACOSX) client_cert_store = new net::ClientCertStoreMac(); -#elif defined(USE_OPENSSL) - // OpenSSL does not use the ClientCertStore infrastructure. - client_cert_store = nullptr; #else -#error Unknown platform. + // OpenSSL does not use the ClientCertStore infrastructure. + client_cert_store = nullptr; #endif // The callback is uncancellable, and GetClientCert requires selected_certs // and client_cert_store to stay alive until the callback is called. So we
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index fff00bb..e060eeb 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2714,8 +2714,8 @@ crbug.com/604642 [ Mac ] fast/text/midword-break-after-breakable-char.html [ Failure ] crbug.com/605024 [ Mac ] svg/transforms/animated-path-inside-transformed-html.xhtml [ Failure ] -crbug.com/605047 [ Mac10.11 ] fast/text/emphasis.html [ Failure ] -crbug.com/605047 [ Mac10.11 ] fast/text/international/complex-character-based-fallback.html [ Failure ] +crbug.com/605047 [ Mac10.11 Retina ] fast/text/emphasis.html [ Failure ] +crbug.com/605047 [ Mac10.11 Retina ] fast/text/international/complex-character-based-fallback.html [ Failure ] crbug.com/605059 [ Retina ] fast/text/international/bidi-neutral-directionality-paragraph-start.html [ Failure ] crbug.com/605059 [ Retina ] fast/text/international/bidi-AN-after-empty-run.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/apply-inline-style-to-element-with-no-renderer-crash.html b/third_party/WebKit/LayoutTests/editing/execCommand/apply-inline-style-to-element-with-no-renderer-crash.html index 3cba805..1f0f5f2 100644 --- a/third_party/WebKit/LayoutTests/editing/execCommand/apply-inline-style-to-element-with-no-renderer-crash.html +++ b/third_party/WebKit/LayoutTests/editing/execCommand/apply-inline-style-to-element-with-no-renderer-crash.html
@@ -25,7 +25,7 @@ input=document.createElement('input'); textPath.parentNode.insertBefore(input, textPath); - window.getSelection().setBaseAndExtent(input, 4); + window.getSelection().setBaseAndExtent(input, 4, null, 0); document.designMode='on'; document.execCommand('Transpose');
diff --git a/third_party/WebKit/LayoutTests/editing/selection/script-tests/DOMSelection-DocumentType.js b/third_party/WebKit/LayoutTests/editing/selection/script-tests/DOMSelection-DocumentType.js index d44f417b..e82d6ab8 100644 --- a/third_party/WebKit/LayoutTests/editing/selection/script-tests/DOMSelection-DocumentType.js +++ b/third_party/WebKit/LayoutTests/editing/selection/script-tests/DOMSelection-DocumentType.js
@@ -3,7 +3,7 @@ var sel = window.getSelection(); var docType = document.implementation.createDocumentType('c', null, null); -sel.setBaseAndExtent(docType); +sel.setBaseAndExtent(docType, 0, null, 0); shouldBeNull("sel.anchorNode"); sel.setBaseAndExtent(null, 0, docType, 0);
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/float-list-changed-before-layout-crash.html b/third_party/WebKit/LayoutTests/fast/block/float/float-list-changed-before-layout-crash.html index 0a5d32a6..70bc0a6 100644 --- a/third_party/WebKit/LayoutTests/fast/block/float/float-list-changed-before-layout-crash.html +++ b/third_party/WebKit/LayoutTests/fast/block/float/float-list-changed-before-layout-crash.html
@@ -6,7 +6,7 @@ } #el1:nth-last-child(2n) { display: table-header-group; - } + } #el2:first-child { display: inline-table; } @@ -15,7 +15,7 @@ } #el2 { display: table-header-group; - } + } #el4 { visibility: collapse; } @@ -24,7 +24,7 @@ } #el5 { display: table-header-group; - } + } #el6 { -webkit-border-after: solid; float: left; @@ -64,7 +64,7 @@ el7.setAttribute('id','el7') document.body.appendChild(el7) document.designMode='on' - window.getSelection().setBaseAndExtent(el3, 1) + window.getSelection().setBaseAndExtent(el3, 1, null, 0) document.execCommand('InsertLineBreak') document.execCommand('selectall') document.execCommand('strikethrough')
diff --git a/third_party/WebKit/LayoutTests/fast/css-generated-content/crash-selection-editing-removes-pseudo.html b/third_party/WebKit/LayoutTests/fast/css-generated-content/crash-selection-editing-removes-pseudo.html index 18e3374..f498565 100644 --- a/third_party/WebKit/LayoutTests/fast/css-generated-content/crash-selection-editing-removes-pseudo.html +++ b/third_party/WebKit/LayoutTests/fast/css-generated-content/crash-selection-editing-removes-pseudo.html
@@ -31,7 +31,7 @@ var test = document.getElementById('test'); // Select from the #start backwards to the start of the line. -window.getSelection().setBaseAndExtent(document.getElementById('start')); +window.getSelection().collapse(document.getElementById('start')); window.getSelection().modify('extend', 'backward', 'lineBoundary') // Replace the selection with a break. This replaces #before, text,
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set-expected.txt index d25615d9..33972e2 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set-expected.txt
@@ -28,6 +28,8 @@ PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" Test grid-template-areas: inherit PASS window.getComputedStyle(parentElement).getPropertyValue('grid-template-areas') is "\"foo bar\"" +PASS window.getComputedStyle(parentElement).getPropertyValue('grid-template-areas') is "\"foo bar\"" +PASS window.getComputedStyle(parentElement).getPropertyValue('grid-template-areas') is "\"foo bar\"" PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "\"foo bar\"" Test invalid grid-template-areas values. PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" @@ -35,6 +37,10 @@ PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" +PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" +PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" +PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" +PASS window.getComputedStyle(element).getPropertyValue('grid-template-areas') is "none" FIXME: We currently don't validate that the named grid areas are <indent>. FAIL window.getComputedStyle(element).getPropertyValue('grid-template-areas') should be none. Was "nav-up".
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set.html index 98ddb9e..4495c27 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-areas-get-set.html
@@ -155,6 +155,10 @@ document.body.appendChild(parentElement); parentElement.style.gridTemplateAreas = "'foo bar'"; shouldBeEqualToString("window.getComputedStyle(parentElement).getPropertyValue('grid-template-areas')", '"foo bar"') + parentElement.style.gridTemplateAreas = "'foo" + "\t" + "bar'"; + shouldBeEqualToString("window.getComputedStyle(parentElement).getPropertyValue('grid-template-areas')", '"foo bar"') + parentElement.style.gridTemplateAreas = "'foo" + "\n" + "bar'"; + shouldBeEqualToString("window.getComputedStyle(parentElement).getPropertyValue('grid-template-areas')", '"foo bar"') var element = document.createElement("div"); parentElement.appendChild(element); @@ -186,6 +190,16 @@ element.style.gridTemplateAreas = "'' ''"; shouldBeEqualToString("window.getComputedStyle(element).getPropertyValue('grid-template-areas')", "none") + element.style.gridTemplateAreas = "'^nav'"; + shouldBeEqualToString("window.getComputedStyle(element).getPropertyValue('grid-template-areas')", "none") + element.style.gridTemplateAreas = "'n^av'"; + shouldBeEqualToString("window.getComputedStyle(element).getPropertyValue('grid-template-areas')", "none") + + element.style.gridTemplateAreas = "'\x04nav'"; + shouldBeEqualToString("window.getComputedStyle(element).getPropertyValue('grid-template-areas')", "none") + element.style.gridTemplateAreas = "'n\x04av'"; + shouldBeEqualToString("window.getComputedStyle(element).getPropertyValue('grid-template-areas')", "none") + debug(""); debug("FIXME: We currently don't validate that the named grid areas are <indent>."); // <ident> only allows a leading '-'.
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment-expected.txt new file mode 100644 index 0000000..16ecae3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment-expected.txt
@@ -0,0 +1,37 @@ +Test that computed style for grid-template-columns and grid-template-rows works as expected with content alignment and gaps. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS window.getComputedStyle(gridContentStart, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentStart, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridContentCenter, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentCenter, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridContentEnd, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentEnd, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridContentSpaceBetween, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentSpaceBetween, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridContentSpaceAround, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentSpaceAround, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridContentSpaceEvenly, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentSpaceEvenly, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridContentStretch, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridContentStretch, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentStart, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentStart, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentCenter, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentCenter, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentEnd, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentEnd, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentSpaceBetween, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentSpaceBetween, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentSpaceAround, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentSpaceAround, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentSpaceEvenly, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentSpaceEvenly, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS window.getComputedStyle(gridGapsContentStretch, '').getPropertyValue('grid-template-columns') is "300px 200px 100px" +PASS window.getComputedStyle(gridGapsContentStretch, '').getPropertyValue('grid-template-rows') is "150px 100px 50px" +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment.html new file mode 100644 index 0000000..8b1c5c6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment.html
@@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<link href="resources/grid.css" rel="stylesheet"> +<link href="resources/grid-alignment.css" rel="stylesheet"> +<style> +.grid { + grid-template-columns: 300px 200px 100px; + grid-template-rows: 150px 100px 50px; + width: 800px; + height: 500px; +} + +.gaps { + grid-gap: 10px 20px; +} +</style> + +<div class="grid contentStart" id="gridContentStart"></div> +<div class="grid contentCenter" id="gridContentCenter"></div> +<div class="grid contentEnd" id="gridContentEnd"></div> +<div class="grid contentSpaceBetween" id="gridContentSpaceBetween"></div> +<div class="grid contentSpaceAround" id="gridContentSpaceAround"></div> +<div class="grid contentSpaceEvenly" id="gridContentSpaceEvenly"></div> +<div class="grid contentStretch" id="gridContentStretch"></div> + +<div class="grid gaps contentStart" id="gridGapsContentStart"></div> +<div class="grid gaps contentCenter" id="gridGapsContentCenter"></div> +<div class="grid gaps contentEnd" id="gridGapsContentEnd"></div> +<div class="grid gaps contentSpaceBetween" id="gridGapsContentSpaceBetween"></div> +<div class="grid gaps contentSpaceAround" id="gridGapsContentSpaceAround"></div> +<div class="grid gaps contentSpaceEvenly" id="gridGapsContentSpaceEvenly"></div> +<div class="grid gaps contentStretch" id="gridGapsContentStretch"></div> + +<script src="../../resources/js-test.js"></script> +<script src="resources/grid-definitions-parsing-utils.js"></script> +<script> + description("Test that computed style for grid-template-columns and grid-template-rows works as expected with content alignment and gaps."); + + testGridDefinitionsValues(document.getElementById("gridContentStart"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridContentCenter"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridContentEnd"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridContentSpaceBetween"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridContentSpaceAround"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridContentSpaceEvenly"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridContentStretch"), "300px 200px 100px", "150px 100px 50px"); + + testGridDefinitionsValues(document.getElementById("gridGapsContentStart"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridGapsContentCenter"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridGapsContentEnd"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridGapsContentSpaceBetween"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridGapsContentSpaceAround"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridGapsContentSpaceEvenly"), "300px 200px 100px", "150px 100px 50px"); + testGridDefinitionsValues(document.getElementById("gridGapsContentStretch"), "300px 200px 100px", "150px 100px 50px"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments-expected.txt index 755a35e..3c41d1f 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments-expected.txt
@@ -1,6 +1,10 @@ PASS selection.addRange() threw exception TypeError: Failed to execute 'addRange' on 'Selection': 1 argument required, but only 0 present.. PASS selection.getRangeAt() threw exception TypeError: Failed to execute 'getRangeAt' on 'Selection': 1 argument required, but only 0 present.. PASS selection.selectAllChildren() threw exception TypeError: Failed to execute 'selectAllChildren' on 'Selection': 1 argument required, but only 0 present.. +PASS selection.setBaseAndExtent() threw exception TypeError: Failed to execute 'setBaseAndExtent' on 'Selection': 4 arguments required, but only 0 present.. +PASS selection.setBaseAndExtent(node) threw exception TypeError: Failed to execute 'setBaseAndExtent' on 'Selection': 4 arguments required, but only 1 present.. +PASS selection.setBaseAndExtent(node, 0) threw exception TypeError: Failed to execute 'setBaseAndExtent' on 'Selection': 4 arguments required, but only 2 present.. +PASS selection.setBaseAndExtent(node, 0, node) threw exception TypeError: Failed to execute 'setBaseAndExtent' on 'Selection': 4 arguments required, but only 3 present.. PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments.html b/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments.html index 7a6fced7..22762386 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments.html +++ b/third_party/WebKit/LayoutTests/fast/dom/Selection/missing-arguments.html
@@ -6,9 +6,14 @@ <body> <script> var selection = getSelection(); +var node = document.body; shouldThrow("selection.addRange()"); shouldThrow("selection.getRangeAt()"); shouldThrow("selection.selectAllChildren()"); +shouldThrow("selection.setBaseAndExtent()"); +shouldThrow("selection.setBaseAndExtent(node)"); +shouldThrow("selection.setBaseAndExtent(node, 0)"); +shouldThrow("selection.setBaseAndExtent(node, 0, node)"); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/non-numeric-values-numeric-parameters-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/non-numeric-values-numeric-parameters-expected.txt index c687974..49bf88870 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/non-numeric-values-numeric-parameters-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/non-numeric-values-numeric-parameters-expected.txt
@@ -56,7 +56,7 @@ PASS nonNumericPolicy('document.createRange().isPointInRange(document, x)') is 'any type allowed (but not omitted)' PASS nonNumericPolicy('getSelection().collapse(document, x)') is 'any type allowed' PASS nonNumericPolicy('getSelection().setBaseAndExtent(document, x, document, 0)') is 'any type allowed' -PASS nonNumericPolicy('getSelection().setBaseAndExtent(document, 0, document, x)') is 'any type allowed' +PASS nonNumericPolicy('getSelection().setBaseAndExtent(document, 0, document, x)') is 'any type allowed (but not omitted)' PASS nonNumericPolicy('getSelection().collapse(document, x)') is 'any type allowed' PASS nonNumericPolicy('getSelection().extend(document, x)') is 'any type allowed' PASS nonNumericPolicy('getSelection().getRangeAt(x)') is 'any type allowed (but not omitted)'
diff --git a/third_party/WebKit/LayoutTests/fast/dom/script-tests/non-numeric-values-numeric-parameters.js b/third_party/WebKit/LayoutTests/fast/dom/script-tests/non-numeric-values-numeric-parameters.js index 472b66a..a056201 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/script-tests/non-numeric-values-numeric-parameters.js +++ b/third_party/WebKit/LayoutTests/fast/dom/script-tests/non-numeric-values-numeric-parameters.js
@@ -304,7 +304,7 @@ shouldBe("nonNumericPolicy('getSelection().collapse(document, x)')", "'any type allowed'"); shouldBe("nonNumericPolicy('getSelection().setBaseAndExtent(document, x, document, 0)')", "'any type allowed'"); -shouldBe("nonNumericPolicy('getSelection().setBaseAndExtent(document, 0, document, x)')", "'any type allowed'"); +shouldBe("nonNumericPolicy('getSelection().setBaseAndExtent(document, 0, document, x)')", "'any type allowed (but not omitted)'"); shouldBe("nonNumericPolicy('getSelection().collapse(document, x)')", "'any type allowed'"); shouldBe("nonNumericPolicy('getSelection().extend(document, x)')", "'any type allowed'"); shouldBe("nonNumericPolicy('getSelection().getRangeAt(x)')", "'any type allowed (but not omitted)'"); @@ -397,7 +397,7 @@ ../../../../WebCore/html/HTMLInputElement.idl: attribute long tabIndex; ../../../../WebCore/html/HTMLInputElement.idl: attribute long selectionStart; ../../../../WebCore/html/HTMLInputElement.idl: attribute long selectionEnd; -../../../../WebCore/html/HTMLLIElement.idl: attribute long value; +../../../../WebCore/html/HTMLLIElement.idl: attribute long value; ../../../../WebCore/html/HTMLMediaElement.idl: attribute unsigned long playCount ../../../../WebCore/html/HTMLMediaElement.idl: attribute unsigned long currentLoop; ../../../../WebCore/html/HTMLObjectElement.idl: attribute long hspace; @@ -429,13 +429,13 @@ ../../../../WebCore/html/CanvasRenderingContext2D.idl: attribute float shadowOffsetY; ../../../../WebCore/html/CanvasRenderingContext2D.idl: attribute float shadowBlur; ../../../../WebCore/html/HTMLMediaElement.idl: attribute float currentTime -../../../../WebCore/html/HTMLMediaElement.idl: attribute float defaultPlaybackRate -../../../../WebCore/html/HTMLMediaElement.idl: attribute float playbackRate +../../../../WebCore/html/HTMLMediaElement.idl: attribute float defaultPlaybackRate +../../../../WebCore/html/HTMLMediaElement.idl: attribute float playbackRate ../../../../WebCore/html/HTMLMediaElement.idl: attribute float start; ../../../../WebCore/html/HTMLMediaElement.idl: attribute float end; ../../../../WebCore/html/HTMLMediaElement.idl: attribute float loopStart; ../../../../WebCore/html/HTMLMediaElement.idl: attribute float loopEnd; -../../../../WebCore/html/HTMLMediaElement.idl: attribute float volume +../../../../WebCore/html/HTMLMediaElement.idl: attribute float volume ../../../../WebCore/svg/SVGAnimatedInteger.idl: attribute long baseVal ../../../../WebCore/svg/SVGElementInstanceList.idl: SVGElementInstance item(in unsigned long index); @@ -459,14 +459,14 @@ ../../../../WebCore/svg/SVGSVGElement.idl: unsigned long suspendRedraw(in unsigned long maxWaitMilliseconds); ../../../../WebCore/svg/SVGSVGElement.idl: void unsuspendRedraw(in unsigned long suspendHandleId) ../../../../WebCore/svg/SVGTextContentElement.idl: long getNumberOfChars(); -../../../../WebCore/svg/SVGTextContentElement.idl: float getSubStringLength(in unsigned long offset, +../../../../WebCore/svg/SVGTextContentElement.idl: float getSubStringLength(in unsigned long offset, ../../../../WebCore/svg/SVGTextContentElement.idl: in unsigned long length) ../../../../WebCore/svg/SVGTextContentElement.idl: SVGPoint getStartPositionOfChar(in unsigned long offset) ../../../../WebCore/svg/SVGTextContentElement.idl: SVGPoint getEndPositionOfChar(in unsigned long offset) ../../../../WebCore/svg/SVGTextContentElement.idl: SVGRect getExtentOfChar(in unsigned long offset) ../../../../WebCore/svg/SVGTextContentElement.idl: float getRotationOfChar(in unsigned long offset) ../../../../WebCore/svg/SVGTextContentElement.idl: long getCharNumAtPosition(in SVGPoint point); -../../../../WebCore/svg/SVGTextContentElement.idl: void selectSubString(in unsigned long offset, +../../../../WebCore/svg/SVGTextContentElement.idl: void selectSubString(in unsigned long offset, ../../../../WebCore/svg/SVGTextContentElement.idl: in unsigned long length) ../../../../WebCore/svg/SVGTransformList.idl: [Custom] SVGTransform getItem(in unsigned long index) ../../../../WebCore/svg/SVGTransformList.idl: [Custom] SVGTransform insertItemBefore(in SVGTransform item, in unsigned long index) @@ -494,7 +494,7 @@ ../../../../WebCore/svg/SVGSVGElement.idl: float getCurrentTime(); ../../../../WebCore/svg/SVGSVGElement.idl: void setCurrentTime(in float seconds); ../../../../WebCore/svg/SVGTextContentElement.idl: float getComputedTextLength(); -../../../../WebCore/svg/SVGTextContentElement.idl: float getSubStringLength(in unsigned long offset, +../../../../WebCore/svg/SVGTextContentElement.idl: float getSubStringLength(in unsigned long offset, ../../../../WebCore/svg/SVGTextContentElement.idl: float getRotationOfChar(in unsigned long offset) ../../../../WebCore/svg/SVGTransform.idl: void setTranslate(in float tx, in float ty); ../../../../WebCore/svg/SVGTransform.idl: void setScale(in float sx, in float sy);
diff --git a/third_party/WebKit/LayoutTests/fast/domurl/url-constructor.html b/third_party/WebKit/LayoutTests/fast/domurl/url-constructor.html index 0128c0c5..4660229 100644 --- a/third_party/WebKit/LayoutTests/fast/domurl/url-constructor.html +++ b/third_party/WebKit/LayoutTests/fast/domurl/url-constructor.html
@@ -53,4 +53,31 @@ function() { new URL('//abc', null); }, 'TypeError: Failed to construct \'URL\': Invalid base URL'); }, 'Invalid URL parameters'); + +test(function() { + function assert_enumerable(p) { + assert_true(p in URL.prototype); + assert_true(URL.prototype.propertyIsEnumerable(p)); + } + + assert_true('URL' in self); + + // TODO: uncomment when implemented. + // assert_true('domainToASCII' in URL); + // assert_true('domainToUnicode' in URL); + + // Arguably better failure stacks to spell them out this way.. + assert_enumerable('toString'); + assert_enumerable('origin'); + assert_enumerable('protocol'); + assert_enumerable('username'); + assert_enumerable('password'); + assert_enumerable('host'); + assert_enumerable('hostname'); + assert_enumerable('port'); + assert_enumerable('pathname'); + assert_enumerable('search'); + assert_enumerable('searchParams'); + assert_enumerable('hash'); +}, 'URL interface'); </script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-data.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-data.html new file mode 100644 index 0000000..aad057d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-data.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html> +<head> +<title>InputEvent: beforeinput data</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +</head> +<body> +<input type="text" id="txt"> +<script> +test(function() { + var lastData = ''; + var txt = document.getElementById('txt'); + txt.addEventListener('beforeinput', function(event) { + lastData = event.data; + }); + if (!window.eventSender) { + document.write('This test requires eventSender'); + } else { + function testKeyDownData(key, modifiers, data) { + eventSender.keyDown(key, modifiers); + assert_equals(lastData, data, `${modifiers.toString()}+${key} should produce data: ${data}`); + } + + txt.focus(); + // Typing + testKeyDownData('a', [], 'a'); + testKeyDownData('4', [], '4'); + testKeyDownData('backspace', [], ''); + // TODO(chongz): eventSender.keyDown('a', ['shiftKey']) should produce shifted character. + // https://crbug.com/604488 + // testKeyDownData('l', ['shiftKey'], 'L'); + // testKeyDownData('6', ['shiftKey'], '^'); + testKeyDownData(' ', [], ' '); + } +}, 'Testing beforeinput data'); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-inputtype.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-inputtype.html new file mode 100644 index 0000000..478fa7a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-inputtype.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> +<head> +<title>InputEvent: beforeinput inputType</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +</head> +<body> +<input type="text" id="txt"> +<script> +test(function() { + var lastInputType = ''; + var txt = document.getElementById('txt'); + txt.addEventListener('beforeinput', function(event) { + lastInputType = event.inputType; + }); + if (!window.eventSender) { + document.write('This test requires eventSender'); + } else { + var kNoBeforeInputFired = 'noBeforeInputFired'; + function testKeyDownInputType(key, modifiers, inputType) { + lastInputType = kNoBeforeInputFired; + eventSender.keyDown(key, modifiers); + assert_equals(lastInputType, inputType, `${modifiers.toString()}+${key} should produce inputType: ${inputType}`); + } + + txt.focus(); + // Typing + testKeyDownInputType('a', [], 'insertText'); + testKeyDownInputType('6', [], 'insertText'); + testKeyDownInputType('backspace', [], 'deleteContent'); + testKeyDownInputType('l', ['shiftKey'], 'insertText'); + testKeyDownInputType('w', ['shiftKey'], 'insertText'); + + // Keyboard commands + var isMacOS = (navigator.userAgent.indexOf('Mac OS X') != -1); + if (!isMacOS) { + // MacOS's eventSender does not work on hot keys other than arrows. + testKeyDownInputType('z', ['ctrlKey'], 'undo'); + testKeyDownInputType('z', ['ctrlKey', 'shiftKey'], 'redo'); + } + // Move command should not generate input events. + testKeyDownInputType('leftArrow', [], kNoBeforeInputFired); + testKeyDownInputType('leftArrow', ['shiftKey'], kNoBeforeInputFired); + testKeyDownInputType('home', [], kNoBeforeInputFired); + } +}, 'Testing beforeinput inputType'); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-order-typing-command.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-order-typing-command.html new file mode 100644 index 0000000..d24eadb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-order-typing-command.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> +<head> +<title>InputEvent: beforeinput order on typing and command</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +</head> +<body> +<input type="text" id="txt"> +<script> +test(function() { + var eventList = ['keydown', 'keypress', 'beforeinput', 'input', 'keyup']; + var expectedEventOrder = [ + // Pressing 'a'. + 'keydown', 'keypress', 'beforeinput', 'input', 'keyup', + // Pressing 'z' with modifier 'ctrlKey'. + 'keydown', 'beforeinput', 'input', 'keyup', + ]; + var actualEventOrder = []; + var txt = document.getElementById('txt'); + eventList.forEach(function(eventType) { + txt.addEventListener(eventType, function(event) { + actualEventOrder.push(event.type); + }); + }); + if (!window.eventSender) { + document.write('This test requires eventSender'); + } else { + txt.focus(); + eventSender.keyDown('a'); + var isMacOSX = navigator.userAgent.indexOf('Mac OS X') != -1; + if (!isMacOSX) { + // MacOS's eventSender does not work on hot keys other than arrows. + eventSender.keyDown('z', ['ctrlKey']); + assert_array_equals(actualEventOrder, expectedEventOrder, actualEventOrder.toString()); + } + } +}, 'Testing beforeinput order on typing and command'); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum-expected.txt b/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum-expected.txt index 773eb29..1c52f9c 100644 --- a/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum-expected.txt
@@ -1,6 +1,5 @@ This tests that the toString() function does not enumerate. -PASS: the toString function is not enumerable for HTMLAnchorElement. PASS: the toString function is not enumerable for Location. PASS: the toString function is not enumerable for Selection. PASS: the toString function is not enumerable for HTMLDivElement.
diff --git a/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum.html b/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum.html index d376d53..05493ca 100644 --- a/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum.html +++ b/third_party/WebKit/LayoutTests/fast/js/toString-dontEnum.html
@@ -25,7 +25,6 @@ testRunner.dumpAsText(); // DOM objects with custom toString() functions - test(document.createElement('a'), "HTMLAnchorElement"); test(window.location, "Location"); test(window.getSelection(), "Selection");
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt index 37860bd0..206c6c758 100644 --- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt
@@ -54,6 +54,8 @@ PASS new webkitRTCPeerConnection({iceServers:[], certificates:[1337]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed sequence<RTCCertificate>. PASS new webkitRTCPeerConnection({iceServers:[], certificates:[certRSA]}, null); did not throw exception. PASS new webkitRTCPeerConnection({iceServers:[], certificates:[certECDSA]}, null); did not throw exception. +PASS certExpired.expires <= new Date().getTime() is true +PASS new webkitRTCPeerConnection({iceServers:[], certificates:[certExpired]}, null); threw exception InvalidStateError: Failed to construct 'RTCPeerConnection': Expired certificate(s).. PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html index 2624d778..577fd44 100644 --- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html +++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html
@@ -66,6 +66,7 @@ // Global certificate variables so that the "should..." methods can evaluate them. var certRSA = null; var certECDSA = null; +var certExpired = null; function testCertificates1RSA() { @@ -86,6 +87,20 @@ .then(function(certificate) { certECDSA = certificate; shouldNotThrow('new webkitRTCPeerConnection({iceServers:[], certificates:[certECDSA]}, null);'); + testCertificates3Expired(); + }, + function() { + testFailed('Generating ECDSA P-256'); + testCertificates3Expired(); + }); +} +function testCertificates3Expired() +{ + webkitRTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256", expires:0 }) + .then(function(certificate) { + certExpired = certificate; + shouldBeTrue('certExpired.expires <= new Date().getTime()'); + shouldThrow('new webkitRTCPeerConnection({iceServers:[], certificates:[certExpired]}, null);'); finishJSTest(); }, function() { @@ -94,7 +109,7 @@ }); } // Sequentially test construction with RSA and ECDSA certificates. -// testCertificates2ECDSA's callback methods mark the end of the async tests. +// testCertificates3Expired's callback methods mark the end of the async tests. testCertificates1RSA(); window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny-expected.txt index 817c493de..a4b9e2b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny-expected.txt
@@ -1,7 +1,5 @@ -http://localhost:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-sameorigin.cgi - willSendRequest <NSURLRequest URL http://localhost:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-sameorigin.cgi, main document URL http://127.0.0.1:8000/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny.html, http method GET> redirectResponse (null) CONSOLE ERROR: Refused to display 'http://localhost:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-sameorigin.cgi' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN, SAMEORIGIN'. -http://localhost:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-sameorigin.cgi - didFinishLoading -CONSOLE MESSAGE: line 17: PASS: Access to contentWindow.location.href threw an exception. +CONSOLE MESSAGE: line 16: PASS: Access to contentWindow.location.href threw an exception. The frame below should not load, proving that 'sameorigin, sameorigin' === 'sameorigin'.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny.html b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny.html index e4804ec..f27f333 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny.html +++ b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-deny.html
@@ -5,7 +5,6 @@ if (window.testRunner) { testRunner.dumpAsText(); testRunner.dumpChildFramesAsText(); - testRunner.dumpResourceLoadCallbacks(); testRunner.waitUntilDone(); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny-expected.txt index 6f2799c..3034b45 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny-expected.txt
@@ -1,7 +1,5 @@ -http://localhost:8000/security/XFrameOptions/resources/x-frame-options-parent-same-origin-allow.cgi - willSendRequest <NSURLRequest URL http://localhost:8000/security/XFrameOptions/resources/x-frame-options-parent-same-origin-allow.cgi, main document URL http://127.0.0.1:8000/security/XFrameOptions/x-frame-options-parent-same-origin-deny.html, http method GET> redirectResponse (null) CONSOLE ERROR: Refused to display 'http://localhost:8000/security/XFrameOptions/resources/x-frame-options-parent-same-origin-allow.cgi' in a frame because it set 'X-Frame-Options' to 'sameorigin'. -http://localhost:8000/security/XFrameOptions/resources/x-frame-options-parent-same-origin-allow.cgi - didFinishLoading -CONSOLE MESSAGE: line 14: PASS: Access to contentWindow.location.href threw an exception. +CONSOLE MESSAGE: line 13: PASS: Access to contentWindow.location.href threw an exception. There should be no content in the iframe below
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny.html b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny.html index 7145cf4b..a6c86b4 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny.html +++ b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-deny.html
@@ -2,7 +2,6 @@ if (window.testRunner) { testRunner.dumpAsText(); testRunner.dumpChildFramesAsText(); - testRunner.dumpResourceLoadCallbacks(); testRunner.waitUntilDone(); }
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt index d9aa8213..5fced73 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -211,6 +211,7 @@ property tagName property textContent property title + property toString property translate property webkitMatchesSelector property webkitRequestFullScreen @@ -1260,6 +1261,7 @@ property tagName property textContent property title + property toString property translate property webkitMatchesSelector property webkitRequestFullScreen
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt index 8821f44..5d0de9e0 100644 --- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -225,6 +225,7 @@ property tagName property textContent property title + property toString property translate property webkitMatchesSelector property webkitRequestFullScreen @@ -1314,6 +1315,7 @@ property tagName property textContent property title + property toString property translate property webkitMatchesSelector property webkitRequestFullScreen
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index b5eb1b3..ccd3ac797 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3391,6 +3391,8 @@ method constructor interface InputEvent : UIEvent attribute @@toStringTag + getter data + getter inputType method constructor interface IntersectionObserver attribute @@toStringTag
diff --git a/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md b/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md index 28d0e01..65b85b16 100644 --- a/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md +++ b/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md
@@ -1269,6 +1269,32 @@ The `[SetWrapperReferenceTo]` extended attribute takes a value, which is the method name to call to get the target object. For example, with the above declaration a call will be made to `YYY::targetMethod()` to get the target of the reference. +### [TraceWrappers=(list)] _(i)_ + +Summary: This generates code that traces script-wrappable references (which are used to keep wrappers alive during V8 GC). + +Usage: `[TraceWrappers=(list)]` can be specified on an interface. + +```webidl +[ + TraceWrappers=(element1, element2) +] interface XXX : YYY { ... }; +``` + +The generator generates a function called `XXX::traceWrappers` which is called by `ScriptWrappableVisitor` during V8 GC. The function adds references from the XXX instance to this object's element1() and element2() children. + +The generated code is then: + +```c++ +DEFINE_TRACE_WRAPPERS(XXX) +{ + visitor->traceWrappers(element1()); + visitor->traceWrappers(element2()); + + YYY::traceWrappers(visitor); +} +``` + ## Rare Blink-specific IDL Extended Attributes These extended attributes are rarely used, generally only in one or two places. These are often replacements for `[Custom]` bindings, and may be candidates for deprecation and removal.
diff --git a/third_party/WebKit/Source/bindings/IDLExtendedAttributes.txt b/third_party/WebKit/Source/bindings/IDLExtendedAttributes.txt index 9cd3ebb..37a7a066 100644 --- a/third_party/WebKit/Source/bindings/IDLExtendedAttributes.txt +++ b/third_party/WebKit/Source/bindings/IDLExtendedAttributes.txt
@@ -88,6 +88,7 @@ # Source/core/page/RuntimeEnabledFeatures.in RuntimeEnabled=* SameObject +TraceWrappers=* SetWrapperReferenceFrom=* SetWrapperReferenceTo=* SetterCallWith=ExecutionContext|ScriptArguments|CurrentWindow|EnteredWindow
diff --git a/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.cpp b/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.cpp index 437bf83..fe1e210 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.cpp
@@ -4,6 +4,7 @@ #include "bindings/core/v8/ActiveScriptWrappable.h" +#include "bindings/core/v8/ScriptWrappable.h" #include "wtf/HashSet.h" #include "wtf/ThreadSpecific.h" #include "wtf/Threading.h" @@ -38,4 +39,14 @@ return m_scriptWrappable; } +void ActiveScriptWrappable::traceActiveScriptWrappables(ScriptWrappableVisitor* visitor) +{ + for (auto activeWrappable : activeScriptWrappables()) { + if (!activeWrappable->hasPendingActivity()) + continue; + + visitor->traceWrappers(activeWrappable->toScriptWrappable()); + } +} + } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.h b/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.h index aab62ff..d5804194 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.h +++ b/third_party/WebKit/Source/bindings/core/v8/ActiveScriptWrappable.h
@@ -11,6 +11,7 @@ namespace blink { class ScriptWrappable; +class ScriptWrappableVisitor; /** * Classes deriving from ActiveScriptWrappable will be registered in a @@ -22,6 +23,8 @@ public: explicit ActiveScriptWrappable(ScriptWrappable*); + static void traceActiveScriptWrappables(ScriptWrappableVisitor*); + virtual bool hasPendingActivity() const = 0; ScriptWrappable* toScriptWrappable() const;
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h b/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h index 62484cd..476c4e3 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h +++ b/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h
@@ -153,6 +153,11 @@ return m_wrapperMap->newLocal(isolate, object); } + void markWrapper(ScriptWrappable* scriptWrappable) + { + m_wrapperMap->markWrapper(scriptWrappable); + } + void setReference(const v8::Persistent<v8::Object>& parent, ScriptWrappable* child, v8::Isolate* isolate) { if (m_isMainWorld) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h index 33da418..ff04464 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h +++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h
@@ -93,6 +93,11 @@ m_map.Remove(key); } + void markWrapper(KeyType* object) + { + m_map.RegisterExternallyReferencedObject(object); + } + private: class PersistentValueMapTraits { STATIC_ONLY(PersistentValueMapTraits);
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp index 82d8d0d..3faa6aaa 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp
@@ -136,6 +136,27 @@ worlds.append(it->value); } +void DOMWrapperWorld::markWrappersInAllWorlds(ScriptWrappable* scriptWrappable, v8::Isolate* isolate) +{ + // TODO(hlopko): Currently wrapper in one world will keep wrappers in all + // worlds alive (possibly holding on entire documents). This is neither + // needed (there is no way to get from one wrapper to another), nor wanted + // (big performance and memory overhead). + + // Marking for the main world + scriptWrappable->markWrapper(isolate); + if (!isMainThread()) + return; + WorldMap& isolatedWorlds = isolatedWorldMap(); + for (auto& keyValuePair : isolatedWorlds) { + DOMDataStore& dataStore = keyValuePair.value->domDataStore(); + if (dataStore.containsWrapper(scriptWrappable)) { + // Marking for the isolated worlds + dataStore.markWrapper(scriptWrappable); + } + } +} + DOMWrapperWorld::~DOMWrapperWorld() { ASSERT(!isMainWorld());
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h index 317ce4b..27c3cc1 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h +++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h
@@ -54,6 +54,7 @@ }; class DOMObjectHolderBase; +class DOMWrapperWorldVisitor; template<typename T> class DOMObjectHolder; // This class represent a collection of DOM wrappers for a specific world. @@ -69,6 +70,7 @@ static bool isolatedWorldsExist() { return isolatedWorldCount; } static void allWorldsInMainThread(Vector<RefPtr<DOMWrapperWorld>>& worlds); + static void markWrappersInAllWorlds(ScriptWrappable*, v8::Isolate*); static DOMWrapperWorld& world(v8::Local<v8::Context> context) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp index 3534a4e..3c44ae6 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp
@@ -35,4 +35,10 @@ return V8DOMWrapper::associateObjectWithWrapper(isolate, this, wrapperTypeInfo, wrapper); } +void ScriptWrappable::markWrapper(v8::Isolate* isolate) const +{ + if (containsWrapper()) + ScriptWrappableVisitor::markWrapper(m_wrapper, isolate); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.h b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.h index a6150c7..31597a0 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.h
@@ -31,6 +31,7 @@ #ifndef ScriptWrappable_h #define ScriptWrappable_h +#include "bindings/core/v8/ScriptWrappableVisitor.h" #include "bindings/core/v8/WrapperTypeInfo.h" #include "core/CoreExport.h" #include "platform/heap/Handle.h" @@ -149,6 +150,15 @@ bool containsWrapper() const { return !m_wrapper.IsEmpty(); } + /** + * Mark wrapper of this ScriptWrappable as alive in V8. Only marks + * wrapper in the main world. To mark wrappers in all worlds call + * ScriptWrappableVisitor::markWrapper(ScriptWrappable*, v8::Isolate*) + */ + void markWrapper(v8::Isolate*) const; + + DECLARE_VIRTUAL_TRACE_WRAPPERS() {}; + // With Oilpan we don't need a ScriptWrappable destructor. // // 'RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper())' is not needed
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp new file mode 100644 index 0000000..bb28a752 --- /dev/null +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp
@@ -0,0 +1,104 @@ +// Copyright 2016 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 "bindings/core/v8/ScriptWrappableVisitor.h" + +#include "bindings/core/v8/ActiveScriptWrappable.h" +#include "bindings/core/v8/DOMDataStore.h" +#include "bindings/core/v8/ScriptWrappable.h" +#include "bindings/core/v8/WrapperTypeInfo.h" +#include "core/dom/NodeRareData.h" +#include "core/events/EventListenerMap.h" +#include "core/events/EventTarget.h" +#include "platform/heap/HeapPage.h" + +namespace blink { + +ScriptWrappableVisitor::~ScriptWrappableVisitor() +{ +} + +void ScriptWrappableVisitor::TracePrologue() +{ + m_tracingInProgress = true; + ActiveScriptWrappable::traceActiveScriptWrappables(this); +} + +void ScriptWrappableVisitor::TraceEpilogue() +{ + for (auto header : m_headersToUnmark) + header->unmarkWrapperHeader(); + + m_headersToUnmark.clear(); + m_tracingInProgress = false; +} + +void ScriptWrappableVisitor::TraceWrappersFrom(const std::vector<std::pair<void*, void*>>& internalFieldsOfPotentialWrappers) +{ + ASSERT(m_tracingInProgress); + for (auto pair : internalFieldsOfPotentialWrappers) { + traceWrappersFrom(pair); + } +} + +void ScriptWrappableVisitor::traceWrappersFrom(std::pair<void*, void*> internalFields) +{ + if (reinterpret_cast<WrapperTypeInfo*>(internalFields.first)->ginEmbedder != gin::GinEmbedder::kEmbedderBlink) + return; + + ScriptWrappable* scriptWrappable = reinterpret_cast<ScriptWrappable*>(internalFields.second); + ASSERT(scriptWrappable->wrapperTypeInfo()->wrapperClassId == WrapperTypeInfo::NodeClassId + || scriptWrappable->wrapperTypeInfo()->wrapperClassId == WrapperTypeInfo::ObjectClassId); + + traceWrappers(scriptWrappable); +} + +bool ScriptWrappableVisitor::isHeaderMarked(const void* garbageCollected) const +{ + return HeapObjectHeader::fromPayload(garbageCollected)->isWrapperHeaderMarked(); +} + +void ScriptWrappableVisitor::markHeader(const void* garbageCollected) const +{ + HeapObjectHeader* header = HeapObjectHeader::fromPayload(garbageCollected); + header->markWrapperHeader(); + addHeaderToUnmark(header); +} + +void ScriptWrappableVisitor::markHeader(const ScriptWrappable* scriptWrappable) const +{ + markHeader(static_cast<const void*>(scriptWrappable)); + + markWrappersInAllWorlds(scriptWrappable, m_isolate); +} + +void ScriptWrappableVisitor::addHeaderToUnmark(HeapObjectHeader* header) const +{ + m_headersToUnmark.append(header); +} + +void ScriptWrappableVisitor::markWrapper(const v8::Persistent<v8::Object>& handle, v8::Isolate* isolate) +{ + handle.RegisterExternalReference(isolate); +} + +void ScriptWrappableVisitor::markWrappersInAllWorlds(const ScriptWrappable* scriptWrappable, v8::Isolate* isolate) +{ + DOMWrapperWorld::markWrappersInAllWorlds(const_cast<ScriptWrappable*>(scriptWrappable), isolate); +} + +void ScriptWrappableVisitor::traceWrappers(const ScriptWrappable* wrappable) const +{ + if (wrappable && !isHeaderMarked(wrappable)) { + markHeader(wrappable); + wrappable->traceWrappers(this); + } +} + +void ScriptWrappableVisitor::traceWrappers(const ScriptWrappable& wrappable) const +{ + traceWrappers(&wrappable); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h new file mode 100644 index 0000000..a26c8e5 --- /dev/null +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
@@ -0,0 +1,106 @@ +// Copyright 2016 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 ScriptWrappableVisitor_h +#define ScriptWrappableVisitor_h + +#include "platform/heap/HeapAllocator.h" +#include <v8.h> +#include <vector> + + +namespace blink { + +class HeapObjectHeader; +class ScriptWrappable; +class ScriptWrappableHeapTracer; +class NodeRareData; + +/** + * Declares non-virtual traceWrappers method. Should be used on + * non-ScriptWrappable classes which should participate in wrapper tracing (e.g. + * NodeRareData): + * + * class NodeRareData { + * public: + * DECLARE_TRACE_WRAPPERS(); + * } + */ +#define DECLARE_TRACE_WRAPPERS() \ + void traceWrappers(const ScriptWrappableVisitor*) const + +/** + * Declares virtual traceWrappers method. It is used in ScriptWrappable, can be + * used to override the method in the subclasses, and can be used by + * non-ScriptWrappable classes which expect to be inherited. + */ +#define DECLARE_VIRTUAL_TRACE_WRAPPERS() \ + virtual DECLARE_TRACE_WRAPPERS() + +/** + * Provides definition of traceWrappers method. Custom code will usually call + * visitor->traceWrappers with all objects which could contribute to the set of + * reachable wrappers: + * + * DEFINE_TRACE_WRAPPERS(NodeRareData) + * { + * visitor->traceWrappers(m_nodeLists); + * visitor->traceWrappers(m_mutationObserverData); + * } + */ +#define DEFINE_TRACE_WRAPPERS(T) \ + void T::traceWrappers(const ScriptWrappableVisitor* visitor) const + +/** + * ScriptWrappableVisitor is able to trace through the script wrappable + * references. It is used during V8 garbage collection. When this visitor is + * set to the v8::Isolate as its embedder heap tracer, V8 will call it during + * its garbage collection. At the beginning, it will call TracePrologue, then + * repeatedly (as v8 discovers more wrappers) it will call TraceWrappersFrom, + * and at the end it will call TraceEpilogue. + */ +class ScriptWrappableVisitor : public v8::EmbedderHeapTracer { +public: + ScriptWrappableVisitor(v8::Isolate* isolate) : m_isolate(isolate) {}; + ~ScriptWrappableVisitor() override; + /** + * Mark wrappers in all worlds for the given script wrappable as alive in + * V8. + */ + static void markWrappersInAllWorlds(const ScriptWrappable*, v8::Isolate*); + /** + * Mark given wrapper as alive in V8. + */ + static void markWrapper(const v8::Persistent<v8::Object>& handle, v8::Isolate*); + + void TracePrologue() override; + void TraceWrappersFrom(const std::vector<std::pair<void*, void*>>& internalFieldsOfPotentialWrappers) override; + void TraceEpilogue() override; + + inline void addHeaderToUnmark(HeapObjectHeader*) const; + void traceWrappers(const ScriptWrappable* wrappable) const; + void traceWrappers(const ScriptWrappable& wrappable) const; +private: + inline void traceWrappersFrom(std::pair<void*, void*> internalFields); + inline void markHeader(const ScriptWrappable* scriptWrappable) const; + inline void markHeader(const void* garbageCollected) const; + inline bool isHeaderMarked(const void* garbageCollected) const; + bool m_tracingInProgress = false; + /** + * Collection of headers we need to unmark after the tracing finished. We + * assume it is safe to hold on to the headers because: + * * oilpan objects cannot move + * * objects this headers belong to are considered alive by the oilpan + * gc (so they cannot be reclaimed). For the oilpan gc, wrappers are + * part of the root set and wrapper will keep its ScriptWrappable + * alive. Wrapper reachability is a subgraph of oilpan reachability, + * therefore anything we find during tracing wrappers will be found by + * oilpan gc too. + */ + mutable WTF::Vector<HeapObjectHeader*> m_headersToUnmark; + v8::Isolate* m_isolate; +}; + +} +#endif
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingDesign.md b/third_party/WebKit/Source/bindings/core/v8/V8BindingDesign.md index 5c98972..2a76b980 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8BindingDesign.md +++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingDesign.md
@@ -137,7 +137,8 @@ an isolated world and a worker world. A main world is a world where a normal JavaScript downloaded from the web is executed. -An isolated world is a world where a content script of a Chrome extension. +An isolated world is a world where a content script of a Chrome extension is +executed. An isolate of the main thread has 1 main world and N isolated worlds. An isolate of a worker thread has 1 worker world and 0 isolated world. [This diagram](https://drive.google.com/file/d/0B1obCOyvTnPKQmJEWkVtOEN2TmM/view?usp=sharing)
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp index f110bad..70a0efc 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -32,6 +32,7 @@ #include "bindings/core/v8/ActiveScriptWrappable.h" #include "bindings/core/v8/RetainedDOMInfo.h" +#include "bindings/core/v8/ScriptWrappableVisitor.h" #include "bindings/core/v8/V8AbstractEventListener.h" #include "bindings/core/v8/V8Binding.h" #include "bindings/core/v8/V8MutationObserver.h" @@ -168,7 +169,7 @@ if (type->hasPendingActivity(wrapper)) { // If you hit this assert, you'll need to add a [DependentiLifetime] // extended attribute to the DOM interface. A DOM interface that - // overrides hasPendingActivity must be marked as [DependentiLifetime]. + // overrides hasPendingActivity must be marked as [DependentLifetime]. RELEASE_ASSERT(!value->IsIndependent()); m_isolate->SetObjectGroupId(*value, liveRootId()); ++m_domObjectsWithPendingActivity; @@ -259,6 +260,9 @@ void gcPrologueForMajorGC(v8::Isolate* isolate, bool constructRetainedObjectInfos) { + if (RuntimeEnabledFeatures::traceWrappablesEnabled()) + return; + objectGroupingForMajorGC(isolate, constructRetainedObjectInfos); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp index e89a717..2282dac 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -334,6 +334,10 @@ { isolate->AddGCPrologueCallback(V8GCController::gcPrologue); isolate->AddGCEpilogueCallback(V8GCController::gcEpilogue); + if (RuntimeEnabledFeatures::traceWrappablesEnabled()) { + ScriptWrappableVisitor* visitor = new ScriptWrappableVisitor(isolate); + isolate->SetEmbedderHeapTracer(visitor); + } v8::Debug::SetLiveEditEnabled(isolate, false);
diff --git a/third_party/WebKit/Source/bindings/core/v8/v8.gypi b/third_party/WebKit/Source/bindings/core/v8/v8.gypi index a748fb0..eabe3d8 100644 --- a/third_party/WebKit/Source/bindings/core/v8/v8.gypi +++ b/third_party/WebKit/Source/bindings/core/v8/v8.gypi
@@ -127,6 +127,8 @@ 'V8EventListenerList.h', 'V8GCController.cpp', 'V8GCController.h', + 'ScriptWrappableVisitor.cpp', + 'ScriptWrappableVisitor.h', 'V8GCForContextDispose.cpp', 'V8GCForContextDispose.h', 'V8GlobalValueMap.h',
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_interface.py b/third_party/WebKit/Source/bindings/scripts/v8_interface.py index f82a0579..6e565e4 100644 --- a/third_party/WebKit/Source/bindings/scripts/v8_interface.py +++ b/third_party/WebKit/Source/bindings/scripts/v8_interface.py
@@ -145,11 +145,16 @@ } set_wrapper_reference_to['idl_type'].add_includes_for_type() - # [SetWrapperReferenceFrom] + # [Custom=VisitDOMWrapper] has_visit_dom_wrapper = ( has_extended_attribute_value(interface, 'Custom', 'VisitDOMWrapper') or set_wrapper_reference_from or set_wrapper_reference_to) + # [TraceWrappers] + trace_wrappers = extended_attribute_value_as_list(interface, 'TraceWrappers') + if trace_wrappers: + includes.add('bindings/core/v8/ScriptWrappableVisitor.h') + wrapper_class_id = ('NodeClassId' if inherits_interface(interface.name, 'Node') else 'ObjectClassId') v8_class_name = v8_utilities.v8_class_name(interface) @@ -168,6 +173,7 @@ 'has_custom_legacy_call_as_function': has_extended_attribute_value(interface, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFunction] 'has_partial_interface': len(interface.partial_interfaces) > 0, 'has_visit_dom_wrapper': has_visit_dom_wrapper, + 'trace_wrappers': trace_wrappers, 'header_includes': header_includes, 'interface_name': interface.name, 'is_array_buffer_or_view': is_array_buffer_or_view, @@ -178,7 +184,7 @@ 'is_node': inherits_interface(interface.name, 'Node'), 'is_partial': interface.is_partial, 'is_typed_array_type': is_typed_array_type, - 'lifetime': 'Dependent' if (has_visit_dom_wrapper or is_dependent_lifetime) else 'Independent', + 'lifetime': 'Dependent' if (has_visit_dom_wrapper or trace_wrappers or is_dependent_lifetime) else 'Independent', 'measure_as': v8_utilities.measure_as(interface, None), # [MeasureAs] 'origin_trial_enabled_function': v8_utilities.origin_trial_enabled_function_name(interface, None), 'parent_interface': parent_interface,
diff --git a/third_party/WebKit/Source/bindings/templates/interface.cpp b/third_party/WebKit/Source/bindings/templates/interface.cpp index 2b9d96f..4d3ec220 100644 --- a/third_party/WebKit/Source/bindings/templates/interface.cpp +++ b/third_party/WebKit/Source/bindings/templates/interface.cpp
@@ -534,6 +534,21 @@ {% endif %} {% endblock %} +{##############################################################################} + +{% block trace_wrappers %} +{% if trace_wrappers %} +DEFINE_TRACE_WRAPPERS({{cpp_class_or_partial}}) +{ + {% for traceable in trace_wrappers %} + visitor->traceWrappers({{traceable}}()); + {% endfor %} + {% if parent_interface %} + {{parent_interface}}::traceWrappers(visitor); + {% endif %} +} +{% endif %} +{% endblock %} {##############################################################################} {% block visit_dom_wrapper %}
diff --git a/third_party/WebKit/Source/bindings/templates/interface_base.cpp b/third_party/WebKit/Source/bindings/templates/interface_base.cpp index ceda80d..42ac08e 100644 --- a/third_party/WebKit/Source/bindings/templates/interface_base.cpp +++ b/third_party/WebKit/Source/bindings/templates/interface_base.cpp
@@ -198,6 +198,7 @@ } // namespace {{cpp_class_or_partial}}V8Internal {% block visit_dom_wrapper %}{% endblock %} +{% block trace_wrappers %}{% endblock %} {##############################################################################} {% block install_attributes %} {% from 'attributes.cpp' import attribute_configuration with context %}
diff --git a/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface.idl b/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface.idl index a5ccf532..8ce95aa 100644 --- a/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface.idl +++ b/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface.idl
@@ -40,6 +40,7 @@ Iterable, RuntimeEnabled=FeatureName, SetWrapperReferenceTo(TestInterface referencedName), + TraceWrappers=(firstChild,nextSibling,prevSibling,parent), Exposed=(Worker,Window), ] interface TestInterface : TestInterfaceEmpty { // members needed to test [ImplementedAs], as this affect attribute
diff --git a/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface3.idl b/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface3.idl index 4470f7c..de08b550 100644 --- a/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface3.idl +++ b/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface3.idl
@@ -49,4 +49,6 @@ [RuntimeEnabled=FeatureName] iterable<any>; [RuntimeEnabled=FeatureName, CallWith=ScriptState, RaisesException, ImplementedAs=iterableKeys] Iterator keys(); + + stringifier readonly attribute DOMString readonlyStringifierAttribute; };
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp index 5195ef7..8fe86bdf 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp
@@ -11,6 +11,7 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptState.h" #include "bindings/core/v8/ScriptValue.h" +#include "bindings/core/v8/ScriptWrappableVisitor.h" #include "bindings/core/v8/UnionTypesCore.h" #include "bindings/core/v8/V8AbstractEventListener.h" #include "bindings/core/v8/V8DOMConfiguration.h" @@ -1979,6 +1980,14 @@ } } +DEFINE_TRACE_WRAPPERS(TestInterfaceImplementation) +{ + visitor->traceWrappers(firstChild()); + visitor->traceWrappers(nextSibling()); + visitor->traceWrappers(prevSibling()); + visitor->traceWrappers(parent()); + TestInterfaceEmpty::traceWrappers(visitor); +} // Suppress warning: global constructors, because AttributeConfiguration is trivial // and does not depend on another global objects. #if defined(COMPONENT_BUILD) && defined(WIN32) && COMPILER(CLANG)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp index d5081ac..228435e1 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp
@@ -39,6 +39,18 @@ namespace TestInterface3V8Internal { +static void readonlyStringifierAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) +{ + v8::Local<v8::Object> holder = info.Holder(); + TestInterface3* impl = V8TestInterface3::toImpl(holder); + v8SetReturnValueString(info, impl->readonlyStringifierAttribute(), info.GetIsolate()); +} + +static void readonlyStringifierAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) +{ + TestInterface3V8Internal::readonlyStringifierAttributeAttributeGetter(info); +} + static void voidMethodDocumentMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { @@ -149,6 +161,17 @@ TestInterface3V8Internal::forEachMethod(info); } +static void toStringMethod(const v8::FunctionCallbackInfo<v8::Value>& info) +{ + TestInterface3* impl = V8TestInterface3::toImpl(info.Holder()); + v8SetReturnValueString(info, impl->readonlyStringifierAttribute(), info.GetIsolate()); +} + +static void toStringMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) +{ + TestInterface3V8Internal::toStringMethod(info); +} + static void iteratorMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { ExceptionState exceptionState(ExceptionState::ExecutionContext, "iterator", "TestInterface3", info.Holder(), info.GetIsolate()); @@ -209,8 +232,13 @@ } // namespace TestInterface3V8Internal +const V8DOMConfiguration::AccessorConfiguration V8TestInterface3Accessors[] = { + {"readonlyStringifierAttribute", TestInterface3V8Internal::readonlyStringifierAttributeAttributeGetterCallback, 0, 0, 0, 0, v8::DEFAULT, static_cast<v8::PropertyAttribute>(v8::ReadOnly), V8DOMConfiguration::ExposedToAllScripts, V8DOMConfiguration::OnPrototype, V8DOMConfiguration::CheckHolder}, +}; + const V8DOMConfiguration::MethodConfiguration V8TestInterface3Methods[] = { {"voidMethodDocument", TestInterface3V8Internal::voidMethodDocumentMethodCallback, 0, 1, v8::None, V8DOMConfiguration::ExposedToAllScripts, V8DOMConfiguration::OnPrototype}, + {"toString", TestInterface3V8Internal::toStringMethodCallback, 0, 0, v8::None, V8DOMConfiguration::ExposedToAllScripts, V8DOMConfiguration::OnPrototype}, }; static void installV8TestInterface3Template(v8::Isolate* isolate, const DOMWrapperWorld& world, v8::Local<v8::FunctionTemplate> interfaceTemplate) @@ -224,6 +252,7 @@ v8::Local<v8::ObjectTemplate> prototypeTemplate = interfaceTemplate->PrototypeTemplate(); ALLOW_UNUSED_LOCAL(prototypeTemplate); // Register DOM constants, attributes and operations. + V8DOMConfiguration::installAccessors(isolate, world, instanceTemplate, prototypeTemplate, interfaceTemplate, signature, V8TestInterface3Accessors, WTF_ARRAY_LENGTH(V8TestInterface3Accessors)); V8DOMConfiguration::installMethods(isolate, world, instanceTemplate, prototypeTemplate, interfaceTemplate, signature, V8TestInterface3Methods, WTF_ARRAY_LENGTH(V8TestInterface3Methods)); // Indexed properties
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.cpp index 210977f..c5b280d2 100644 --- a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.cpp
@@ -9,6 +9,7 @@ #include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/PrivateScriptRunner.h" #include "bindings/core/v8/ScriptPromise.h" +#include "bindings/core/v8/ScriptWrappableVisitor.h" #include "bindings/core/v8/V8DOMConfiguration.h" #include "bindings/core/v8/V8Document.h" #include "bindings/core/v8/V8Node.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl index bfdc7cba..d531966 100644 --- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
@@ -7,14 +7,16 @@ #include <string> #include "platform/PlatformExport.h" -#include "wtf/build_config.h" +#include "wtf/Allocator.h" #include "wtf/Forward.h" +#include "wtf/build_config.h" namespace blink { // A class that stores static enablers for all experimental features. class PLATFORM_EXPORT RuntimeEnabledFeatures { + STATIC_ONLY(RuntimeEnabledFeatures); public: class PLATFORM_EXPORT Backup { public: @@ -53,8 +55,6 @@ {% endfor %} private: - RuntimeEnabledFeatures() { } - {% for feature in standard_features %} static bool is{{feature.name}}Enabled; {% endfor %}
diff --git a/third_party/WebKit/Source/core/css/CSSMarkup.cpp b/third_party/WebKit/Source/core/css/CSSMarkup.cpp index d038527..55987e9 100644 --- a/third_party/WebKit/Source/core/css/CSSMarkup.cpp +++ b/third_party/WebKit/Source/core/css/CSSMarkup.cpp
@@ -26,6 +26,7 @@ #include "core/css/CSSMarkup.h" +#include "core/css/parser/CSSParserIdioms.h" #include "wtf/HexNumber.h" #include "wtf/text/StringBuffer.h" #include "wtf/text/StringBuilder.h" @@ -42,13 +43,13 @@ ++characters; // {nmstart} - if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0]))) + if (characters == end || !isNameStartCodePoint(characters[0])) return false; ++characters; // {nmchar}* for (; characters != end; ++characters) { - if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0]))) + if (!isNameCodePoint(characters[0])) return false; }
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 4b9e74e5..e4083c36 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -644,18 +644,20 @@ CSSValueList* list = CSSValueList::createSpaceSeparated(); size_t insertionIndex; if (isLayoutGrid) { - const Vector<LayoutUnit>& trackPositions = direction == ForColumns ? toLayoutGrid(layoutObject)->columnPositions() : toLayoutGrid(layoutObject)->rowPositions(); + const auto* grid = toLayoutGrid(layoutObject); + const Vector<LayoutUnit>& trackPositions = direction == ForColumns ? grid->columnPositions() : grid->rowPositions(); // There are at least #tracks + 1 grid lines (trackPositions). Apart from that, the grid container can generate implicit grid tracks, // so we'll have more trackPositions than trackSizes as the latter only contain the explicit grid. ASSERT(trackPositions.size() - 1 >= trackSizes.size()); size_t i; - LayoutUnit gutterSize = toLayoutGrid(layoutObject)->guttersSize(direction, 2); + LayoutUnit gutterSize = grid->guttersSize(direction, 2); + LayoutUnit offsetBetweenTracks = grid->offsetBetweenTracks(direction); for (i = 0; i < trackPositions.size() - 2; ++i) { addValuesForNamedGridLinesAtIndex(orderedNamedGridLines, i, *list); - list->append(zoomAdjustedPixelValue(trackPositions[i + 1] - trackPositions[i] - gutterSize, style)); + list->append(zoomAdjustedPixelValue(trackPositions[i + 1] - trackPositions[i] - gutterSize - offsetBetweenTracks, style)); } - // Last track line does not have any gutter. + // Last track line does not have any gutter or distribution offset. addValuesForNamedGridLinesAtIndex(orderedNamedGridLines, i, *list); list->append(zoomAdjustedPixelValue(trackPositions[i + 1] - trackPositions[i], style)); insertionIndex = trackPositions.size() - 1;
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp index 92f06db..d720cb9a 100644 --- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp +++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
@@ -173,6 +173,20 @@ return false; } +bool compareDoubleValue(double a, double b, MediaFeaturePrefix op) +{ + const double precision = std::numeric_limits<double>::epsilon(); + switch (op) { + case MinPrefix: + return a >= (b - precision); + case MaxPrefix: + return a <= (b + precision); + case NoPrefix: + return std::abs(a - b) <= precision; + } + return false; +} + static bool compareAspectRatioValue(const MediaQueryExpValue& value, int width, int height, MediaFeaturePrefix op) { if (value.isRatio) @@ -374,7 +388,7 @@ static bool computeLengthAndCompare(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues, double compareToValue) { double length; - return computeLength(value, mediaValues, length) && compareValue(compareToValue, length, op); + return computeLength(value, mediaValues, length) && compareDoubleValue(compareToValue, length, op); } static bool deviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp index 2cb2eb368..3f4fdab 100644 --- a/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp +++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
@@ -115,6 +115,18 @@ {0, 0} // Do not remove the terminator line. }; +TestCase floatNonFriendlyViewportTestCases[] = { + {"(min-width: 821px)", 1}, + {"(max-width: 821px)", 1}, + {"(width: 821px)", 1}, + {"(min-height: 821px)", 1}, + {"(max-height: 821px)", 1}, + {"(height: 821px)", 1}, + {"(width: 100vw)", 1}, + {"(height: 100vh)", 1}, + {0, 0} // Do not remove the terminator line. +}; + TestCase printTestCases[] = { {"print and (min-resolution: 1dppx)", 1}, {"print and (min-resolution: 118dpcm)", 1}, @@ -127,7 +139,7 @@ Persistent<MediaQuerySet> querySet = nullptr; for (unsigned i = 0; testCases[i].input; ++i) { querySet = MediaQuerySet::create(testCases[i].input); - ASSERT_EQ(testCases[i].output, mediaQueryEvaluator.eval(querySet.get())); + EXPECT_EQ(testCases[i].output, mediaQueryEvaluator.eval(querySet.get())); } } @@ -193,4 +205,15 @@ testMQEvaluator(floatViewportTestCases, mediaQueryEvaluator); } +TEST(MediaQueryEvaluatorTest, CachedFloatViewportNonFloatFriendly) +{ + MediaValuesCached::MediaValuesCachedData data; + data.viewportWidth = 821; + data.viewportHeight = 821; + MediaValues* mediaValues = MediaValuesCached::create(data); + + MediaQueryEvaluator mediaQueryEvaluator(*mediaValues); + testMQEvaluator(floatNonFriendlyViewportTestCases, mediaQueryEvaluator); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/MediaValues.cpp b/third_party/WebKit/Source/core/css/MediaValues.cpp index 6f7cbc2..2b52736 100644 --- a/third_party/WebKit/Source/core/css/MediaValues.cpp +++ b/third_party/WebKit/Source/core/css/MediaValues.cpp
@@ -159,61 +159,52 @@ // CSSToLengthConversionData::zoomedComputedPixels() more generic (to solve both cases) without hurting performance. // FIXME - Unite the logic here with CSSToLengthConversionData in a performant way. - double factor = 0; switch (type) { case CSSPrimitiveValue::UnitType::Ems: case CSSPrimitiveValue::UnitType::Rems: - factor = defaultFontSize; - break; + result = value * defaultFontSize; + return true; case CSSPrimitiveValue::UnitType::Pixels: case CSSPrimitiveValue::UnitType::UserUnits: - factor = 1; - break; + result = value; + return true; case CSSPrimitiveValue::UnitType::Exs: // FIXME: We have a bug right now where the zoom will be applied twice to EX units. - // FIXME: We don't seem to be able to cache fontMetrics related values. - // Trying to access them is triggering some sort of microtask. Serving the spec's default instead. - factor = defaultFontSize / 2.0; - break; case CSSPrimitiveValue::UnitType::Chs: // FIXME: We don't seem to be able to cache fontMetrics related values. - // Trying to access them is triggering some sort of microtask. Serving the (future) spec default instead. - factor = defaultFontSize / 2.0; - break; + // Trying to access them is triggering some sort of microtask. Serving the spec's default instead. + result = (value * defaultFontSize) / 2.0; + return true; case CSSPrimitiveValue::UnitType::ViewportWidth: - factor = viewportWidth / 100.0; - break; + result = (value * viewportWidth) / 100.0; + return true; case CSSPrimitiveValue::UnitType::ViewportHeight: - factor = viewportHeight / 100.0; - break; + result = (value * viewportHeight) / 100.0; + return true; case CSSPrimitiveValue::UnitType::ViewportMin: - factor = std::min(viewportWidth, viewportHeight) / 100.0; - break; + result = (value * std::min(viewportWidth, viewportHeight)) / 100.0; + return true; case CSSPrimitiveValue::UnitType::ViewportMax: - factor = std::max(viewportWidth, viewportHeight) / 100.0; - break; + result = (value * std::max(viewportWidth, viewportHeight)) / 100.0; + return true; case CSSPrimitiveValue::UnitType::Centimeters: - factor = cssPixelsPerCentimeter; - break; + result = value * cssPixelsPerCentimeter; + return true; case CSSPrimitiveValue::UnitType::Millimeters: - factor = cssPixelsPerMillimeter; - break; + result = value * cssPixelsPerMillimeter; + return true; case CSSPrimitiveValue::UnitType::Inches: - factor = cssPixelsPerInch; - break; + result = value * cssPixelsPerInch; + return true; case CSSPrimitiveValue::UnitType::Points: - factor = cssPixelsPerPoint; - break; + result = value * cssPixelsPerPoint; + return true; case CSSPrimitiveValue::UnitType::Picas: - factor = cssPixelsPerPica; - break; + result = value * cssPixelsPerPica; + return true; default: return false; } - - ASSERT(factor >= 0); - result = value * factor; - return true; } LocalFrame* MediaValues::frameFrom(Document& document)
diff --git a/third_party/WebKit/Source/core/css/MediaValuesTest.cpp b/third_party/WebKit/Source/core/css/MediaValuesTest.cpp index af9176bb0..3ff0e48 100644 --- a/third_party/WebKit/Source/core/css/MediaValuesTest.cpp +++ b/third_party/WebKit/Source/core/css/MediaValuesTest.cpp
@@ -17,7 +17,7 @@ unsigned viewportWidth; unsigned viewportHeight; bool success; - int output; + double output; }; TEST(MediaValuesTest, Basic) @@ -28,15 +28,16 @@ { 40.0, CSSPrimitiveValue::UnitType::Rems, 16, 300, 300, true, 640 }, { 40.0, CSSPrimitiveValue::UnitType::Exs, 16, 300, 300, true, 320 }, { 40.0, CSSPrimitiveValue::UnitType::Chs, 16, 300, 300, true, 320 }, - { 43.0, CSSPrimitiveValue::UnitType::ViewportWidth, 16, 848, 976, true, 364 }, - { 43.0, CSSPrimitiveValue::UnitType::ViewportHeight, 16, 848, 976, true, 419 }, - { 43.0, CSSPrimitiveValue::UnitType::ViewportMin, 16, 848, 976, true, 364 }, - { 43.0, CSSPrimitiveValue::UnitType::ViewportMax, 16, 848, 976, true, 419 }, - { 1.3, CSSPrimitiveValue::UnitType::Centimeters, 16, 300, 300, true, 49 }, - { 1.3, CSSPrimitiveValue::UnitType::Millimeters, 16, 300, 300, true, 4 }, - { 1.3, CSSPrimitiveValue::UnitType::Inches, 16, 300, 300, true, 124 }, - { 13, CSSPrimitiveValue::UnitType::Points, 16, 300, 300, true, 17 }, - { 1.3, CSSPrimitiveValue::UnitType::Picas, 16, 300, 300, true, 20 }, + { 43.0, CSSPrimitiveValue::UnitType::ViewportWidth, 16, 848, 976, true, 364.64 }, + { 100.0, CSSPrimitiveValue::UnitType::ViewportWidth, 16, 821, 976, true, 821 }, + { 43.0, CSSPrimitiveValue::UnitType::ViewportHeight, 16, 848, 976, true, 419.68 }, + { 43.0, CSSPrimitiveValue::UnitType::ViewportMin, 16, 848, 976, true, 364.64 }, + { 43.0, CSSPrimitiveValue::UnitType::ViewportMax, 16, 848, 976, true, 419.68 }, + { 1.3, CSSPrimitiveValue::UnitType::Centimeters, 16, 300, 300, true, 49.133858 }, + { 1.3, CSSPrimitiveValue::UnitType::Millimeters, 16, 300, 300, true, 4.913386 }, + { 1.3, CSSPrimitiveValue::UnitType::Inches, 16, 300, 300, true, 124.8 }, + { 13, CSSPrimitiveValue::UnitType::Points, 16, 300, 300, true, 17.333333 }, + { 1.3, CSSPrimitiveValue::UnitType::Picas, 16, 300, 300, true, 20.8 }, { 40.0, CSSPrimitiveValue::UnitType::UserUnits, 16, 300, 300, true, 40 }, { 1.3, CSSPrimitiveValue::UnitType::Unknown, 16, 300, 300, false, 20 }, { 0.0, CSSPrimitiveValue::UnitType::Unknown, 0, 0, 0, false, 0.0 } // Do not remove the terminating line. @@ -44,16 +45,16 @@ for (unsigned i = 0; testCases[i].viewportWidth; ++i) { - int output = 0; + double output = 0; bool success = MediaValues::computeLength(testCases[i].value, testCases[i].type, testCases[i].fontSize, testCases[i].viewportWidth, testCases[i].viewportHeight, output); - ASSERT_EQ(testCases[i].success, success); + EXPECT_EQ(testCases[i].success, success); if (success) - ASSERT_EQ(testCases[i].output, output); + EXPECT_FLOAT_EQ(testCases[i].output, output); } }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserIdioms.h b/third_party/WebKit/Source/core/css/parser/CSSParserIdioms.h index b9ad905c..86d7aeca 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserIdioms.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParserIdioms.h
@@ -42,6 +42,20 @@ return c == ' ' || c == '\t' || c == '\n'; } +// http://dev.w3.org/csswg/css-syntax/#name-start-code-point +template <typename CharacterType> +bool isNameStartCodePoint(CharacterType c) +{ + return isASCIIAlpha(c) || c == '_' || !isASCII(c); +} + +// http://dev.w3.org/csswg/css-syntax/#name-code-point +template <typename CharacterType> +bool isNameCodePoint(CharacterType c) +{ + return isNameStartCodePoint(c) || isASCIIDigit(c) || c == '-'; +} + } #endif
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index 5e73636..cf70950 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -37,6 +37,7 @@ #include "core/css/FontFace.h" #include "core/css/HashTools.h" #include "core/css/parser/CSSParserFastPaths.h" +#include "core/css/parser/CSSParserIdioms.h" #include "core/css/parser/CSSPropertyParserHelpers.h" #include "core/css/parser/CSSVariableParser.h" #include "core/frame/UseCounter.h" @@ -3172,10 +3173,7 @@ StringBuilder areaName; for (unsigned i = 0; i < text.length(); ++i) { - // TODO(rob.buis): this whitespace check misses \n and \t. - // https://drafts.csswg.org/css-grid/#valdef-grid-template-areas-string - // https://drafts.csswg.org/css-syntax-3/#whitespace - if (text[i] == ' ') { + if (isCSSSpace(text[i])) { if (!areaName.isEmpty()) { columnNames.append(areaName.toString()); areaName.clear(); @@ -3190,7 +3188,8 @@ areaName.clear(); } } else { - // TODO(rob.buis): only allow name code points here. + if (!isNameCodePoint(text[i])) + return Vector<String>(); if (areaName == ".") { columnNames.append(areaName.toString()); areaName.clear(); @@ -3214,7 +3213,8 @@ Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames); if (rowCount == 0) { columnCount = columnNames.size(); - ASSERT(columnCount); + if (columnCount == 0) + return false; } else if (columnCount != columnNames.size()) { // The declaration is invalid if all the rows don't have the number of columns. return false;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp index 6d4a2abd..a4d30292 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp
@@ -8,6 +8,7 @@ #include "core/CSSTokenizerCodepoints.cpp" } +#include "core/css/parser/CSSParserIdioms.h" #include "core/css/parser/CSSParserObserverWrapper.h" #include "core/css/parser/CSSParserTokenRange.h" #include "core/css/parser/CSSTokenizerInputStream.h" @@ -83,22 +84,6 @@ return m_tokens.size(); } -// http://dev.w3.org/csswg/css-syntax/#name-start-code-point -static bool isNameStart(UChar c) -{ - if (isASCIIAlpha(c)) - return true; - if (c == '_') - return true; - return !isASCII(c); -} - -// http://dev.w3.org/csswg/css-syntax/#name-code-point -static bool isNameChar(UChar c) -{ - return isNameStart(c) || isASCIIDigit(c) || c == '-'; -} - static bool isNewLine(UChar cc) { // We check \r and \f here, since we have no preprocessing stage @@ -271,7 +256,7 @@ CSSParserToken CSSTokenizer::hash(UChar cc) { UChar nextChar = m_input.nextInputChar(); - if (isNameChar(nextChar) || twoCharsAreValidEscape(nextChar, m_input.peek(1))) { + if (isNameCodePoint(nextChar) || twoCharsAreValidEscape(nextChar, m_input.peek(1))) { HashTokenType type = nextCharsAreIdentifier() ? HashTokenId : HashTokenUnrestricted; return CSSParserToken(type, consumeName()); } @@ -684,7 +669,7 @@ UChar cc = m_input.peekWithoutReplacement(size); if (cc == '\0' || cc == '\\') break; - if (!isNameChar(cc)) { + if (!isNameCodePoint(cc)) { unsigned startOffset = m_input.offset(); m_input.advance(size); return m_input.rangeAsCSSParserString(startOffset, size); @@ -694,7 +679,7 @@ StringBuilder result; while (true) { UChar cc = consume(); - if (isNameChar(cc)) { + if (isNameCodePoint(cc)) { result.append(cc); continue; } @@ -765,11 +750,11 @@ bool CSSTokenizer::nextCharsAreIdentifier(UChar first) { UChar second = m_input.nextInputChar(); - if (isNameStart(first) || twoCharsAreValidEscape(first, second)) + if (isNameStartCodePoint(first) || twoCharsAreValidEscape(first, second)) return true; if (first == '-') - return isNameStart(second) || second == '-' || nextTwoCharsAreValidEscape(); + return isNameStartCodePoint(second) || second == '-' || nextTwoCharsAreValidEscape(); return false; }
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 6a7f6d6c..168234f 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -996,7 +996,6 @@ bool isActive() const { return m_lifecycle.isActive(); } bool isDetached() const { return m_lifecycle.state() >= DocumentLifecycle::Stopping; } bool isStopped() const { return m_lifecycle.state() == DocumentLifecycle::Stopped; } - bool isDisposed() const { return m_lifecycle.state() == DocumentLifecycle::Disposed; } enum HttpRefreshType { HttpRefreshFromHeader,
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp index f68a509..382a94d 100644 --- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
@@ -100,8 +100,6 @@ case Inactive: if (nextState == StyleClean) return true; - if (nextState == Disposed) - return true; break; case VisualUpdatePending: if (nextState == InPreLayout) @@ -239,11 +237,7 @@ case Stopping: return nextState == Stopped; case Stopped: - return nextState == Disposed; - case Disposed: - // FIXME: We can dispose a document multiple times. This seems wrong. - // See https://code.google.com/p/chromium/issues/detail?id=301668. - return nextState == Disposed; + return false; } return false; } @@ -320,7 +314,6 @@ DEBUG_STRING_CASE(PaintClean); DEBUG_STRING_CASE(Stopping); DEBUG_STRING_CASE(Stopped); - DEBUG_STRING_CASE(Disposed); } ASSERT_NOT_REACHED();
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.h b/third_party/WebKit/Source/core/dom/DocumentLifecycle.h index f8c98d4..6a2d1f062 100644 --- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.h +++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.h
@@ -80,7 +80,6 @@ // to the style/layout/compositing states. Stopping, Stopped, - Disposed, }; class Scope {
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h index 5f523d02..6e5933f 100644 --- a/third_party/WebKit/Source/core/dom/Node.h +++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -661,6 +661,8 @@ DECLARE_VIRTUAL_TRACE(); + DECLARE_VIRTUAL_TRACE_WRAPPERS(); + unsigned lengthOfContents() const; v8::Local<v8::Object> wrap(v8::Isolate*, v8::Local<v8::Object> creationContext) override;
diff --git a/third_party/WebKit/Source/core/dom/Node.idl b/third_party/WebKit/Source/core/dom/Node.idl index 2dab0ce..9d58923 100644 --- a/third_party/WebKit/Source/core/dom/Node.idl +++ b/third_party/WebKit/Source/core/dom/Node.idl
@@ -22,6 +22,7 @@ [ DependentLifetime, + TraceWrappers=(ownerDocument,parentNode,parentElement,nextSibling,previousSibling,firstChild) ] interface Node : EventTarget { const unsigned short ELEMENT_NODE = 1; // FIXME: Attr should not inherit from Node. crbug.com/305105
diff --git a/third_party/WebKit/Source/core/dom/NodeRareData.cpp b/third_party/WebKit/Source/core/dom/NodeRareData.cpp index 04a158e..86ac338 100644 --- a/third_party/WebKit/Source/core/dom/NodeRareData.cpp +++ b/third_party/WebKit/Source/core/dom/NodeRareData.cpp
@@ -30,6 +30,7 @@ #include "core/dom/NodeRareData.h" +#include "bindings/core/v8/ScriptWrappableVisitor.h" #include "core/dom/Element.h" #include "core/dom/ElementRareData.h" #include "core/frame/FrameHost.h"
diff --git a/third_party/WebKit/Source/core/dom/URL.idl b/third_party/WebKit/Source/core/dom/URL.idl index 35f6f7fe..881851b 100644 --- a/third_party/WebKit/Source/core/dom/URL.idl +++ b/third_party/WebKit/Source/core/dom/URL.idl
@@ -44,16 +44,7 @@ [RaisesException, CallWith=ExecutionContext] static DOMString? createObjectURL(Blob blob); [CallWith=ExecutionContext] static void revokeObjectURL(DOMString url); - // TODO(sof): 'stringifier' entails an enumerable toString(), - // http://heycam.github.io/webidl/#es-stringifier - // something URL currently doesn't provide. Switch it over to being - // enumerable (http://crbug.com/306606). - // - // Until that time, do not use 'stringifier'. - // stringifier attribute USVString href; - attribute USVString href; - [NotEnumerable, ImplementedAs=href] USVString toString(); - + stringifier attribute USVString href; readonly attribute USVString origin; attribute USVString protocol;
diff --git a/third_party/WebKit/Source/core/dom/URLUtilsReadOnly.idl b/third_party/WebKit/Source/core/dom/URLUtilsReadOnly.idl index 9f5aac0..e2cc46d1 100644 --- a/third_party/WebKit/Source/core/dom/URLUtilsReadOnly.idl +++ b/third_party/WebKit/Source/core/dom/URLUtilsReadOnly.idl
@@ -29,10 +29,7 @@ NoInterfaceObject, // Always used on target of 'implements' Exposed=(Window,Worker), ] interface URLUtilsReadOnly { - // FIXME: should be stringifier: http://crbug.com/306606 - // stringifier readonly attribute USVString href; - readonly attribute USVString href; - [NotEnumerable, ImplementedAs=href] USVString toString(); + stringifier readonly attribute USVString href; readonly attribute USVString origin; readonly attribute USVString protocol;
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp index 1009d71..bdfadf91 100644 --- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp +++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -1732,4 +1732,34 @@ return node && node->layoutObject() && node->layoutObject()->style()->textSecurity() != TSNONE; } +DispatchEventResult dispatchBeforeInputInsertText(EventTarget* target, const String& data) +{ + if (!RuntimeEnabledFeatures::inputEventEnabled()) + return DispatchEventResult::NotCanceled; + if (!target) + return DispatchEventResult::NotCanceled; + InputEvent* beforeInputEvent = InputEvent::createBeforeInput(InputEvent::InputType::InsertText, data, InputEvent::EventCancelable::IsCancelable); + return target->dispatchEvent(beforeInputEvent); +} + +DispatchEventResult dispatchBeforeInputFromComposition(EventTarget* target, InputEvent::InputType inputType, const String& data) +{ + if (!RuntimeEnabledFeatures::inputEventEnabled()) + return DispatchEventResult::NotCanceled; + if (!target) + return DispatchEventResult::NotCanceled; + InputEvent* beforeInputEvent = InputEvent::createBeforeInput(inputType, data, InputEvent::EventCancelable::NotCancelable); + return target->dispatchEvent(beforeInputEvent); +} + +DispatchEventResult dispatchBeforeInputEditorCommand(EventTarget* target, InputEvent::InputType inputType, const String& data) +{ + if (!RuntimeEnabledFeatures::inputEventEnabled()) + return DispatchEventResult::NotCanceled; + if (!target) + return DispatchEventResult::NotCanceled; + InputEvent* beforeInputEvent = InputEvent::createBeforeInput(inputType, data, InputEvent::EventCancelable::IsCancelable); + return target->dispatchEvent(beforeInputEvent); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.h b/third_party/WebKit/Source/core/editing/EditingUtilities.h index 18f4cb3..49f2b52 100644 --- a/third_party/WebKit/Source/core/editing/EditingUtilities.h +++ b/third_party/WebKit/Source/core/editing/EditingUtilities.h
@@ -33,6 +33,7 @@ #include "core/editing/PositionWithAffinity.h" #include "core/editing/VisiblePosition.h" #include "core/editing/VisibleSelection.h" +#include "core/events/InputEvent.h" #include "platform/text/TextDirection.h" #include "wtf/Forward.h" #include "wtf/text/CharacterNames.h" @@ -346,6 +347,15 @@ String stringWithRebalancedWhitespace(const String&, bool startIsStartOfParagraph, bool endIsEndOfParagraph); const String& nonBreakingSpaceString(); +// ------------------------------------------------------------------------- +// Events +// ------------------------------------------------------------------------- + +// Functions dispatch InputEvent +DispatchEventResult dispatchBeforeInputInsertText(EventTarget*, const String& data); +DispatchEventResult dispatchBeforeInputFromComposition(EventTarget*, InputEvent::InputType, const String& data); +DispatchEventResult dispatchBeforeInputEditorCommand(EventTarget*, InputEvent::InputType, const String& data = ""); + } // namespace blink #endif
diff --git a/third_party/WebKit/Source/core/editing/EditorKeyBindings.cpp b/third_party/WebKit/Source/core/editing/EditorKeyBindings.cpp index 6f3dca9..589c314 100644 --- a/third_party/WebKit/Source/core/editing/EditorKeyBindings.cpp +++ b/third_party/WebKit/Source/core/editing/EditorKeyBindings.cpp
@@ -26,6 +26,7 @@ #include "core/editing/Editor.h" +#include "core/editing/EditingUtilities.h" #include "core/events/KeyboardEvent.h" #include "core/frame/LocalFrame.h" #include "core/page/EditorClient.h" @@ -60,6 +61,10 @@ if (!behavior().shouldInsertCharacter(*evt) || !canEdit()) return false; + // Return true to prevent default action. e.g. Space key scroll. + if (dispatchBeforeInputInsertText(evt->target(), evt->keyEvent()->text()) != DispatchEventResult::NotCanceled) + return true; + return insertText(evt->keyEvent()->text(), evt); }
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp index e0bec0d..ca051a0c 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -172,6 +172,11 @@ clear(); + // TODO(chongz): DOM update should happen before 'compositionend' and along with 'compositionupdate'. + // https://crbug.com/575294 + if (dispatchBeforeInputInsertText(frame().document()->focusedElement(), text) != DispatchEventResult::NotCanceled) + return false; + insertTextForConfirmedComposition(text); return true; @@ -182,6 +187,10 @@ if (!hasComposition()) { if (!text.length()) return false; + + if (dispatchBeforeInputInsertText(frame().document()->focusedElement(), text) != DispatchEventResult::NotCanceled) + return false; + editor().insertText(text, 0); return true; } @@ -278,8 +287,13 @@ else event = CompositionEvent::create(EventTypeNames::compositionend, frame().domWindow(), text); } - if (event) + if (event) { + // TODO(chongz): Support canceling IME composition. + // TODO(chongz): Should fire InsertText or DeleteComposedCharacter based on action. + if (event->type() == EventTypeNames::compositionupdate) + dispatchBeforeInputFromComposition(target, InputEvent::InputType::InsertText, text); target->dispatchEvent(event); + } } // If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input @@ -453,6 +467,8 @@ break; ++before; } while (frame().selection().start() == frame().selection().end() && before <= static_cast<int>(selectionOffsets.start())); + // TODO(chongz): According to spec |data| should be "forward" or "backward". + dispatchBeforeInputEditorCommand(frame().document()->focusedElement(), InputEvent::InputType::DeleteContent); TypingCommand::deleteSelection(*frame().document()); }
diff --git a/third_party/WebKit/Source/core/editing/Selection.idl b/third_party/WebKit/Source/core/editing/Selection.idl index ad3935ef..19be361 100644 --- a/third_party/WebKit/Source/core/editing/Selection.idl +++ b/third_party/WebKit/Source/core/editing/Selection.idl
@@ -52,12 +52,9 @@ [MeasureAs=SelectionCollapseToEnd, RaisesException] void collapseToEnd(); [MeasureAs=SelectionExtend, RaisesException] void extend(Node node, optional long offset = 0); // TODO(philipj): The arguments should be anchorNode, anchorOffset, - // focusNode and focusOffset, and none of them are optional or nullable in - // the spec. - [MeasureAs=SelectionSetBaseAndExtent, RaisesException] void setBaseAndExtent([Default=Undefined] optional Node? baseNode, - [Default=Undefined] optional long baseOffset, - [Default=Undefined] optional Node? extentNode, - [Default=Undefined] optional long extentOffset); + // focusNode and focusOffset, and none of them are nullable in the spec. + [MeasureAs=SelectionSetBaseAndExtent, RaisesException] void setBaseAndExtent(Node? baseNode, long baseOffset, + Node? extentNode, long extentOffset); [MeasureAs=SelectionSelectAllChildren, RaisesException] void selectAllChildren(Node node); [MeasureAs=SelectionDeleteDromDocument, CustomElementCallbacks] void deleteFromDocument(); [MeasureAs=SelectionContainsNode] boolean containsNode(Node node, optional boolean allowPartialContainment = false);
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp index 82083270..b71feb9 100644 --- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -104,6 +104,33 @@ return WebEditingCommandType::Invalid; } +InputEvent::InputType InputTypeFromCommandType(WebEditingCommandType commandType) +{ + switch (commandType) { + case WebEditingCommandType::Delete: + case WebEditingCommandType::DeleteBackward: + case WebEditingCommandType::DeleteBackwardByDecomposingPreviousCharacter: + case WebEditingCommandType::DeleteForward: + case WebEditingCommandType::DeleteToBeginningOfLine: + case WebEditingCommandType::DeleteToBeginningOfParagraph: + case WebEditingCommandType::DeleteToEndOfLine: + case WebEditingCommandType::DeleteToEndOfParagraph: + case WebEditingCommandType::DeleteToMark: + case WebEditingCommandType::DeleteWordBackward: + case WebEditingCommandType::DeleteWordForward: + return InputEvent::InputType::DeleteContent; + case WebEditingCommandType::Redo: + return InputEvent::InputType::Redo; + case WebEditingCommandType::Undo: + return InputEvent::InputType::Undo; + case WebEditingCommandType::InsertBacktab: + case WebEditingCommandType::InsertText: + return InputEvent::InputType::InsertText; + default: + return InputEvent::InputType::None; + } +} + } // anonymous namespace class EditorInternalCommand { @@ -1751,6 +1778,19 @@ if (!isSupported() || !m_frame || !m_command->allowExecutionWhenDisabled) return false; } + + if (m_source == CommandFromMenuOrKeyBinding) { + InputEvent::InputType inputType = InputTypeFromCommandType(m_command->commandType); + if (inputType != InputEvent::InputType::None) { + if (dispatchBeforeInputEditorCommand(eventTargetNodeForDocument(m_frame->document()), inputType) != DispatchEventResult::NotCanceled) + return true; + } + } + + // 'beforeinput' event handler may destroy |frame()|. + if (!m_frame || !frame().document()) + return false; + frame().document()->updateLayoutIgnorePendingStylesheets(); DEFINE_STATIC_LOCAL(SparseHistogram, commandHistogram, ("WebCore.Editing.Commands")); commandHistogram.sample(static_cast<int>(m_command->commandType));
diff --git a/third_party/WebKit/Source/core/events/EventTypeNames.in b/third_party/WebKit/Source/core/events/EventTypeNames.in index a7f5ac4..f9f9c81 100644 --- a/third_party/WebKit/Source/core/events/EventTypeNames.in +++ b/third_party/WebKit/Source/core/events/EventTypeNames.in
@@ -28,6 +28,7 @@ availablechange beforecopy beforecut +beforeinput beforeinstallprompt beforepaste beforeunload
diff --git a/third_party/WebKit/Source/core/events/InputEvent.cpp b/third_party/WebKit/Source/core/events/InputEvent.cpp index f7eb07a..e5bef79 100644 --- a/third_party/WebKit/Source/core/events/InputEvent.cpp +++ b/third_party/WebKit/Source/core/events/InputEvent.cpp
@@ -5,9 +5,48 @@ #include "core/events/InputEvent.h" #include "core/events/EventDispatcher.h" +#include "public/platform/WebEditingCommandType.h" namespace blink { +namespace { + +const struct { + InputEvent::InputType inputType; + const char* stringName; +} kInputTypeStringNameMap[] = { + {InputEvent::InputType::None, ""}, + {InputEvent::InputType::InsertText, "insertText"}, + {InputEvent::InputType::ReplaceContent, "replaceContent"}, + {InputEvent::InputType::DeleteContent, "deleteContent"}, + {InputEvent::InputType::DeleteComposedCharacter, "deleteComposedCharacter"}, + {InputEvent::InputType::Undo, "undo"}, + {InputEvent::InputType::Redo, "redo"}, +}; + +static_assert(arraysize(kInputTypeStringNameMap) == static_cast<size_t>(InputEvent::InputType::NumberOfInputTypes), + "must handle all InputEvent::InputType"); + +String convertInputTypeToString(InputEvent::InputType inputType) +{ + const auto& it = std::begin(kInputTypeStringNameMap) + static_cast<size_t>(inputType); + if (it >= std::begin(kInputTypeStringNameMap) && it < std::end(kInputTypeStringNameMap)) + return AtomicString(it->stringName); + return emptyString(); +} + +InputEvent::InputType convertStringToInputType(const String& stringName) +{ + // TODO(chongz): Use binary search if the map goes larger. + for (const auto& entry : kInputTypeStringNameMap) { + if (stringName == entry.stringName) + return entry.inputType; + } + return InputEvent::InputType::None; +} + +} // anonymous namespace + InputEvent::InputEvent() { } @@ -15,6 +54,32 @@ InputEvent::InputEvent(const AtomicString& type, const InputEventInit& initializer) : UIEvent(type, initializer) { + // TODO(ojan): We should find a way to prevent conversion like String->enum->String just in order to use initializer. + // See InputEvent::createBeforeInput() for the first conversion. + if (initializer.hasInputType()) + m_inputType = convertStringToInputType(initializer.inputType()); + if (initializer.hasData()) + m_data = initializer.data(); +} + +/* static */ +InputEvent* InputEvent::createBeforeInput(InputType inputType, const String& data, EventCancelable cancelable) +{ + InputEventInit inputEventInit; + + inputEventInit.setBubbles(true); + inputEventInit.setCancelable(cancelable == IsCancelable); + // TODO(ojan): We should find a way to prevent conversion like String->enum->String just in order to use initializer. + // See InputEvent::InputEvent() for the second conversion. + inputEventInit.setInputType(convertInputTypeToString(inputType)); + inputEventInit.setData(data); + + return InputEvent::create(EventTypeNames::beforeinput, inputEventInit); +} + +String InputEvent::inputType() const +{ + return convertInputTypeToString(m_inputType); } bool InputEvent::isInputEvent() const
diff --git a/third_party/WebKit/Source/core/events/InputEvent.h b/third_party/WebKit/Source/core/events/InputEvent.h index 8bfb45ef..4c14550f 100644 --- a/third_party/WebKit/Source/core/events/InputEvent.h +++ b/third_party/WebKit/Source/core/events/InputEvent.h
@@ -24,6 +24,29 @@ return new InputEvent(type, initializer); } + enum class InputType { + None, + InsertText, + ReplaceContent, + DeleteContent, + DeleteComposedCharacter, + Undo, + Redo, + + // Add new input types immediately above this line. + NumberOfInputTypes, + }; + + enum EventCancelable : bool { + NotCancelable = false, + IsCancelable = true, + }; + + static InputEvent* createBeforeInput(InputType, const String& data, EventCancelable); + + String inputType() const; + const String& data() const { return m_data; } + bool isInputEvent() const override; DECLARE_VIRTUAL_TRACE(); @@ -31,6 +54,9 @@ private: InputEvent(); InputEvent(const AtomicString&, const InputEventInit&); + + InputType m_inputType; + String m_data; }; DEFINE_EVENT_TYPE_CASTS(InputEvent);
diff --git a/third_party/WebKit/Source/core/events/InputEvent.idl b/third_party/WebKit/Source/core/events/InputEvent.idl index cc1d595..6d6dfa7 100644 --- a/third_party/WebKit/Source/core/events/InputEvent.idl +++ b/third_party/WebKit/Source/core/events/InputEvent.idl
@@ -8,5 +8,7 @@ Constructor(DOMString type, optional InputEventInit eventInitDict), RuntimeEnabled=InputEvent, ] interface InputEvent : UIEvent { - // TODO(chongz): Add 'inputType', 'data', 'isComposing' and 'targetRanges' + readonly attribute DOMString inputType; + readonly attribute DOMString data; + // TODO(chongz): Add 'isComposing' and 'targetRanges' };
diff --git a/third_party/WebKit/Source/core/events/InputEventInit.idl b/third_party/WebKit/Source/core/events/InputEventInit.idl index 6b2d07d..89c8e09 100644 --- a/third_party/WebKit/Source/core/events/InputEventInit.idl +++ b/third_party/WebKit/Source/core/events/InputEventInit.idl
@@ -7,5 +7,7 @@ [ RuntimeEnabled=InputEvent, ] dictionary InputEventInit : UIEventInit { - // TODO(chongz): Add 'inputType', 'data', 'isComposing' and 'targetRanges' + DOMString inputType = ""; + DOMString data = ""; + // TODO(chongz): Add 'isComposing' and 'targetRanges' };
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 864a48a..363f4c2 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -38,6 +38,7 @@ #include "core/editing/RenderedPosition.h" #include "core/editing/markers/DocumentMarkerController.h" #include "core/fetch/ResourceFetcher.h" +#include "core/frame/EventHandlerRegistry.h" #include "core/frame/FrameHost.h" #include "core/frame/LocalFrame.h" #include "core/frame/Location.h" @@ -1623,7 +1624,7 @@ bool FrameView::computeCompositedSelection(LocalFrame& frame, CompositedSelection& selection) { - if (frame.view()->shouldThrottleRendering()) + if (!frame.view() || frame.view()->shouldThrottleRendering()) return false; const VisibleSelection& visibleSelection = frame.selection().selection(); @@ -4028,9 +4029,10 @@ } bool becameUnthrottled = wasThrottled && !canThrottleRendering(); + ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); if (becameUnthrottled) { // ScrollingCoordinator needs to update according to the new throttling status. - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + if (scrollingCoordinator) scrollingCoordinator->notifyGeometryChanged(); // Start ticking animation frames again if necessary. page()->animator().scheduleVisualUpdate(m_frame.get()); @@ -4040,6 +4042,10 @@ if (LayoutView* layoutView = this->layoutView()) layoutView->invalidatePaintForViewAndCompositedLayers(); } + + bool hasHandlers = m_frame->document()->frameHost()->eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEventBlocking); + if (wasThrottled != canThrottleRendering() && scrollingCoordinator && hasHandlers) + scrollingCoordinator->touchEventTargetRectsDidChange(); } bool FrameView::shouldThrottleRendering() const
diff --git a/third_party/WebKit/Source/core/html/HTMLHyperlinkElementUtils.idl b/third_party/WebKit/Source/core/html/HTMLHyperlinkElementUtils.idl index f30281e..554cb3ad 100644 --- a/third_party/WebKit/Source/core/html/HTMLHyperlinkElementUtils.idl +++ b/third_party/WebKit/Source/core/html/HTMLHyperlinkElementUtils.idl
@@ -7,15 +7,7 @@ [ NoInterfaceObject, // Always used on target of 'implements' ] interface HTMLHyperlinkElementUtils { - // TODO(sof): 'stringifier' entails an enumerable toString(), - // http://heycam.github.io/webidl/#es-stringifier - // something implementations of HTMLHyperlinkElementUtils currently - // provide. Make them to comply with the spec (http://crbug.com/306606). - // - // Until that time, do not use 'stringifier'. - // stringifier attribute USVString href; - attribute USVString href; - [NotEnumerable, ImplementedAs=href] USVString toString(); + stringifier attribute USVString href; readonly attribute USVString origin; attribute USVString protocol;
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp index 93524f6f..560b519 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -225,7 +225,7 @@ bool HTMLInputElement::hasBadInput() const { - return willValidate() && m_inputType->hasBadInput(); + return willValidate() && m_inputTypeView->hasBadInput(); } bool HTMLInputElement::patternMismatch() const @@ -438,7 +438,7 @@ const AtomicString& newTypeName = InputType::normalizeTypeName(fastGetAttribute(typeAttr)); m_inputType = InputType::create(*this, newTypeName); - m_inputTypeView = m_inputType; + m_inputTypeView = m_inputType->createView(); ensureUserAgentShadowRoot(); updateTouchEventHandlerRegistry(); @@ -547,12 +547,12 @@ FormControlState HTMLInputElement::saveFormControlState() const { - return m_inputType->saveFormControlState(); + return m_inputTypeView->saveFormControlState(); } void HTMLInputElement::restoreFormControlState(const FormControlState& state) { - m_inputType->restoreFormControlState(state); + m_inputTypeView->restoreFormControlState(state); m_stateRestored = true; } @@ -637,7 +637,7 @@ void HTMLInputElement::accessKeyAction(bool sendMouseEvents) { - m_inputType->accessKeyAction(sendMouseEvents); + m_inputTypeView->accessKeyAction(sendMouseEvents); } bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const @@ -1211,7 +1211,7 @@ // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element // must dispatch a DOMActivate event - a click event will not do the job. if (evt->type() == EventTypeNames::DOMActivate) { - m_inputType->handleDOMActivateEvent(evt); + m_inputTypeView->handleDOMActivateEvent(evt); if (evt->defaultHandled()) return; } @@ -1858,7 +1858,7 @@ parameters.anchorRectInScreen = document().view()->contentsToScreen(pixelSnappedBoundingBox()); parameters.currentValue = value(); parameters.doubleValue = m_inputType->valueAsDouble(); - parameters.isAnchorElementRTL = m_inputType->computedTextDirection() == RTL; + parameters.isAnchorElementRTL = m_inputTypeView->computedTextDirection() == RTL; if (HTMLDataListElement* dataList = this->dataList()) { HTMLDataListOptionsCollection* options = dataList->options(); for (unsigned i = 0; HTMLOptionElement* option = options->item(i); ++i) {
diff --git a/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.cpp b/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.cpp index 136f2de..159edb84 100644 --- a/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.cpp
@@ -32,6 +32,7 @@ #include "core/html/HTMLInputElement.h" #include "core/html/forms/BaseChooserOnlyDateAndTimeInputType.h" +#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" #include "platform/text/PlatformLocale.h" #include "wtf/CurrentTime.h" #include "wtf/DateMath.h" @@ -47,13 +48,16 @@ static const int msecPerMinute = 60 * 1000; static const int msecPerSecond = 1000; +String BaseDateAndTimeInputType::badInputText() const +{ + return locale().queryString(WebLocalizedString::ValidationBadInputForDateTime); +} + InputTypeView* BaseDateAndTimeInputType::createView() { - if (!RuntimeEnabledFeatures::inputMultipleFieldsUIEnabled()) - return BaseChooserOnlyDateAndTimeInputType::create(element(), *this); - // TODO(tkent): Returns MultipleFieldsDateAndTimeInputTypeView. - // crbug.com/243714 - return this; + if (RuntimeEnabledFeatures::inputMultipleFieldsUIEnabled()) + return BaseMultipleFieldsDateAndTimeInputType::create(element(), *this); + return BaseChooserOnlyDateAndTimeInputType::create(element(), *this); } double BaseDateAndTimeInputType::valueAsDate() const
diff --git a/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.h b/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.h index e6638e1aa4..bbc1eb0 100644 --- a/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.h +++ b/third_party/WebKit/Source/core/html/forms/BaseDateAndTimeInputType.h
@@ -40,9 +40,21 @@ class ExceptionState; // A super class of date, datetime, datetime-local, month, time, and week types. +// TODO(tkent): A single temporal input type creates two InputTypeView instances +// unnecessarily. One is BaseChooserOnlyDateAndTimeInputType or +// BaseMultipleFieldsDateAndTimeInputType, and another is +// BaseDateAndTimeInputType, which inherits from InputTypeView through +// InputType. The latter is not used. class BaseDateAndTimeInputType : public InputType { public: String visibleValue() const override; + String sanitizeValue(const String&) const override; + // Parses the specified string for this InputType, and returns true if it + // is successfully parsed. An instance pointed by the DateComponents* + // parameter will have parsed values and be modified even if the parsing + // fails. The DateComponents* parameter may be 0. + bool parseToDateComponents(const String&, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const = 0; // Provide some helpers for BaseMultipleFieldsDateAndTimeInputType. virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const = 0; @@ -52,20 +64,14 @@ protected: BaseDateAndTimeInputType(HTMLInputElement& element) : InputType(element) { } Decimal parseToNumber(const String&, const Decimal&) const override; - // Parses the specified string for this InputType, and returns true if it - // is successfully parsed. An instance pointed by the DateComponents* - // parameter will have parsed values and be modified even if the parsing - // fails. The DateComponents* parameter may be 0. - bool parseToDateComponents(const String&, DateComponents*) const; - String sanitizeValue(const String&) const override; String serialize(const Decimal&) const override; String serializeWithComponents(const DateComponents&) const; - virtual bool setMillisecondToDateComponents(double, DateComponents*) const = 0; bool shouldHaveSecondField(const DateComponents&) const; private: virtual bool parseToDateComponentsInternal(const String&, DateComponents*) const = 0; + String badInputText() const override; InputTypeView* createView() override; double valueAsDate() const override; void setValueAsDate(double, ExceptionState&) const override;
diff --git a/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp b/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp index 9807bf3..1c4b493 100644 --- a/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
@@ -30,7 +30,6 @@ #include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) #include "core/CSSValueKeywords.h" #include "core/dom/StyleChangeReason.h" #include "core/dom/shadow/ShadowRoot.h" @@ -39,6 +38,7 @@ #include "core/html/HTMLDataListElement.h" #include "core/html/HTMLInputElement.h" #include "core/html/HTMLOptionElement.h" +#include "core/html/forms/BaseDateAndTimeInputType.h" #include "core/html/forms/DateTimeFieldsState.h" #include "core/html/forms/FormController.h" #include "core/html/shadow/ShadowElementNames.h" @@ -68,7 +68,7 @@ void visitField(DateTimeFormat::FieldType, int) final; void visitLiteral(const String&) final { } - bool validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType&); + bool validateFormat(const String& format, const BaseDateAndTimeInputType&); private: bool m_hasYear; @@ -120,7 +120,7 @@ } } -bool DateTimeFormatValidator::validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType& inputType) +bool DateTimeFormatValidator::validateFormat(const String& format, const BaseDateAndTimeInputType& inputType) { if (!DateTimeFormat::parse(format, *this)) return false; @@ -181,7 +181,7 @@ void BaseMultipleFieldsDateAndTimeInputType::editControlValueChanged() { String oldValue = element().value(); - String newValue = sanitizeValue(dateTimeEditElement()->value()); + String newValue = m_inputType->sanitizeValue(dateTimeEditElement()->value()); // Even if oldValue is null and newValue is "", we should assume they are same. if ((oldValue.isEmpty() && newValue.isEmpty()) || oldValue == newValue) { element().setNeedsValidityCheck(); @@ -194,6 +194,11 @@ element().updateClearButtonVisibility(); } +String BaseMultipleFieldsDateAndTimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState& state) const +{ + return m_inputType->formatDateTimeFieldsState(state); +} + bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const { return false; @@ -289,21 +294,28 @@ return element().setupDateTimeChooserParameters(parameters); } -BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element) - : BaseDateAndTimeInputType(element) +BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element, BaseDateAndTimeInputType& inputType) + : InputTypeView(element) + , m_inputType(inputType) , m_isDestroyingShadowSubtree(false) , m_pickerIndicatorIsVisible(false) , m_pickerIndicatorIsAlwaysVisible(false) { } +BaseMultipleFieldsDateAndTimeInputType* BaseMultipleFieldsDateAndTimeInputType::create(HTMLInputElement& element, BaseDateAndTimeInputType& inputType) +{ + return new BaseMultipleFieldsDateAndTimeInputType(element, inputType); +} + BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType() { } -String BaseMultipleFieldsDateAndTimeInputType::badInputText() const +DEFINE_TRACE(BaseMultipleFieldsDateAndTimeInputType) { - return locale().queryString(WebLocalizedString::ValidationBadInputForDateTime); + visitor->trace(m_inputType); + InputTypeView::trace(visitor); } void BaseMultipleFieldsDateAndTimeInputType::blur() @@ -349,7 +361,7 @@ container->appendChild(ClearButtonElement::create(document, *this)); container->appendChild(SpinButtonElement::create(document, *this)); - if (LayoutTheme::theme().supportsCalendarPicker(formControlType())) + if (LayoutTheme::theme().supportsCalendarPicker(m_inputType->formControlType())) m_pickerIndicatorIsAlwaysVisible = true; container->appendChild(PickerIndicatorElement::create(document, *this)); m_pickerIndicatorIsVisible = true; @@ -374,7 +386,7 @@ if (containsFocusedShadowElement()) element().focus(); - BaseDateAndTimeInputType::destroyShadowSubtree(); + InputTypeView::destroyShadowSubtree(); m_isDestroyingShadowSubtree = false; } @@ -468,7 +480,7 @@ return; DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state); edit->setValueAsDateTimeFieldsState(dateTimeFieldsState); - element().setValueInternal(sanitizeValue(edit->value()), DispatchNoEvent); + element().setValueInternal(m_inputType->sanitizeValue(edit->value()), DispatchNoEvent); updateClearButtonVisibility(); } @@ -499,18 +511,18 @@ if (!edit) return; - DateTimeEditElement::LayoutParameters layoutParameters(element().locale(), createStepRange(AnyIsDefaultStep)); + DateTimeEditElement::LayoutParameters layoutParameters(element().locale(), m_inputType->createStepRange(AnyIsDefaultStep)); DateComponents date; bool hasValue = false; if (!element().suggestedValue().isNull()) - hasValue = parseToDateComponents(element().suggestedValue(), &date); + hasValue = m_inputType->parseToDateComponents(element().suggestedValue(), &date); else - hasValue = parseToDateComponents(element().value(), &date); + hasValue = m_inputType->parseToDateComponents(element().value(), &date); if (!hasValue) - setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date); + m_inputType->setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date); - setupLayoutParameters(layoutParameters, date); + m_inputType->setupLayoutParameters(layoutParameters, date); DEFINE_STATIC_LOCAL(AtomicString, datetimeformatAttr, ("datetimeformat")); edit->setAttribute(datetimeformatAttr, AtomicString(layoutParameters.dateTimeFormat), ASSERT_NO_EXCEPTION); @@ -518,7 +530,7 @@ if (!pattern.isEmpty()) layoutParameters.dateTimeFormat = pattern; - if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this)) + if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *m_inputType)) layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat; if (hasValue) @@ -619,5 +631,3 @@ } } // namespace blink - -#endif
diff --git a/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h b/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h index 9b059a1..e603b7f 100644 --- a/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h +++ b/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h
@@ -31,10 +31,7 @@ #ifndef BaseMultipleFieldsDateAndTimeInputType_h #define BaseMultipleFieldsDateAndTimeInputType_h -#include "wtf/build_config.h" - -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) -#include "core/html/forms/BaseDateAndTimeInputType.h" +#include "core/html/forms/InputTypeView.h" #include "core/html/shadow/ClearButtonElement.h" #include "core/html/shadow/DateTimeEditElement.h" #include "core/html/shadow/PickerIndicatorElement.h" @@ -42,10 +39,12 @@ namespace blink { +class BaseDateAndTimeInputType; struct DateTimeChooserParameters; -class BaseMultipleFieldsDateAndTimeInputType - : public BaseDateAndTimeInputType +// TODO(tkent): Rename this to MultipleFieldsTemporalInputTypeView. +class BaseMultipleFieldsDateAndTimeInputType final + : public InputTypeView , protected DateTimeEditElement::EditControlOwner , protected PickerIndicatorElement::PickerIndicatorOwner , protected SpinButtonElement::SpinButtonOwner @@ -53,17 +52,18 @@ USING_GARBAGE_COLLECTED_MIXIN(BaseMultipleFieldsDateAndTimeInputType); public: - DEFINE_INLINE_VIRTUAL_TRACE() { BaseDateAndTimeInputType::trace(visitor); } - -protected: - BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement&); + static BaseMultipleFieldsDateAndTimeInputType* create(HTMLInputElement&, BaseDateAndTimeInputType&); ~BaseMultipleFieldsDateAndTimeInputType() override; + DECLARE_VIRTUAL_TRACE(); private: + BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement&, BaseDateAndTimeInputType&); + // DateTimeEditElement::EditControlOwner functions void didBlurFromControl() final; void didFocusOnControl() final; void editControlValueChanged() final; + String formatDateTimeFieldsState(const DateTimeFieldsState&) const override; bool isEditControlOwnerDisabled() const final; bool isEditControlOwnerReadOnly() const final; AtomicString localeIdentifier() const final; @@ -89,8 +89,7 @@ bool shouldClearButtonRespondToMouseEvents() override; void clearValue() override; - // InputType functions - String badInputText() const override; + // InputTypeView functions void blur() final; void closePopupView() override; PassRefPtr<ComputedStyle> customStyleForLayoutObject(PassRefPtr<ComputedStyle>) override; @@ -125,6 +124,7 @@ void hidePickerIndicator(); void updatePickerIndicatorVisibility(); + Member<BaseDateAndTimeInputType> m_inputType; bool m_isDestroyingShadowSubtree; bool m_pickerIndicatorIsVisible; bool m_pickerIndicatorIsAlwaysVisible; @@ -132,5 +132,4 @@ } // namespace blink -#endif #endif // BaseMultipleFieldsDateAndTimeInputType_h
diff --git a/third_party/WebKit/Source/core/html/forms/DateInputType.cpp b/third_party/WebKit/Source/core/html/forms/DateInputType.cpp index 0a69f9b..15080ce 100644 --- a/third_party/WebKit/Source/core/html/forms/DateInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/DateInputType.cpp
@@ -49,7 +49,7 @@ static const int dateStepScaleFactor = 86400000; inline DateInputType::DateInputType(HTMLInputElement& element) - : BaseDateInputType(element) + : BaseDateAndTimeInputType(element) { }
diff --git a/third_party/WebKit/Source/core/html/forms/DateInputType.h b/third_party/WebKit/Source/core/html/forms/DateInputType.h index 86ba0e7..c6b3236 100644 --- a/third_party/WebKit/Source/core/html/forms/DateInputType.h +++ b/third_party/WebKit/Source/core/html/forms/DateInputType.h
@@ -32,17 +32,10 @@ #define DateInputType_h #include "core/html/forms/BaseDateAndTimeInputType.h" -#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" namespace blink { -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) -using BaseDateInputType = BaseMultipleFieldsDateAndTimeInputType; -#else -using BaseDateInputType = BaseDateAndTimeInputType; -#endif - -class DateInputType final : public BaseDateInputType { +class DateInputType final : public BaseDateAndTimeInputType { public: static InputType* create(HTMLInputElement&);
diff --git a/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h b/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h index 5a4dbf4..6b773b8 100644 --- a/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h +++ b/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h
@@ -32,24 +32,17 @@ #define DateTimeLocalInputType_h #include "core/html/forms/BaseDateAndTimeInputType.h" -#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" namespace blink { class ExceptionState; -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) -using BaseDateTimeLocalInputType = BaseMultipleFieldsDateAndTimeInputType; -#else -using BaseDateTimeLocalInputType = BaseDateAndTimeInputType; -#endif - -class DateTimeLocalInputType final : public BaseDateTimeLocalInputType { +class DateTimeLocalInputType final : public BaseDateAndTimeInputType { public: static InputType* create(HTMLInputElement&); private: - explicit DateTimeLocalInputType(HTMLInputElement& element) : BaseDateTimeLocalInputType(element) { } + explicit DateTimeLocalInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) {} void countUsage() override; const AtomicString& formControlType() const override;
diff --git a/third_party/WebKit/Source/core/html/forms/MonthInputType.h b/third_party/WebKit/Source/core/html/forms/MonthInputType.h index 1016917e..f9d12156 100644 --- a/third_party/WebKit/Source/core/html/forms/MonthInputType.h +++ b/third_party/WebKit/Source/core/html/forms/MonthInputType.h
@@ -32,22 +32,15 @@ #define MonthInputType_h #include "core/html/forms/BaseDateAndTimeInputType.h" -#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" namespace blink { -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) -using BaseMonthInputType = BaseMultipleFieldsDateAndTimeInputType; -#else -using BaseMonthInputType = BaseDateAndTimeInputType; -#endif - -class MonthInputType final : public BaseMonthInputType { +class MonthInputType final : public BaseDateAndTimeInputType { public: static InputType* create(HTMLInputElement&); private: - explicit MonthInputType(HTMLInputElement& element) : BaseMonthInputType(element) { } + explicit MonthInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) {} void countUsage() override; const AtomicString& formControlType() const override;
diff --git a/third_party/WebKit/Source/core/html/forms/TimeInputType.cpp b/third_party/WebKit/Source/core/html/forms/TimeInputType.cpp index a5f9583..36ac43dd 100644 --- a/third_party/WebKit/Source/core/html/forms/TimeInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/TimeInputType.cpp
@@ -53,7 +53,7 @@ static const int timeStepScaleFactor = 1000; TimeInputType::TimeInputType(HTMLInputElement& element) - : BaseTimeInputType(element) + : BaseDateAndTimeInputType(element) { }
diff --git a/third_party/WebKit/Source/core/html/forms/TimeInputType.h b/third_party/WebKit/Source/core/html/forms/TimeInputType.h index 3def9ae..8644f09 100644 --- a/third_party/WebKit/Source/core/html/forms/TimeInputType.h +++ b/third_party/WebKit/Source/core/html/forms/TimeInputType.h
@@ -32,17 +32,10 @@ #define TimeInputType_h #include "core/html/forms/BaseDateAndTimeInputType.h" -#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" namespace blink { -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) -using BaseTimeInputType = BaseMultipleFieldsDateAndTimeInputType; -#else -using BaseTimeInputType = BaseDateAndTimeInputType; -#endif - -class TimeInputType final : public BaseTimeInputType { +class TimeInputType final : public BaseDateAndTimeInputType { public: static InputType* create(HTMLInputElement&);
diff --git a/third_party/WebKit/Source/core/html/forms/WeekInputType.h b/third_party/WebKit/Source/core/html/forms/WeekInputType.h index 16163188..b5f9563a 100644 --- a/third_party/WebKit/Source/core/html/forms/WeekInputType.h +++ b/third_party/WebKit/Source/core/html/forms/WeekInputType.h
@@ -32,22 +32,15 @@ #define WeekInputType_h #include "core/html/forms/BaseDateAndTimeInputType.h" -#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h" namespace blink { -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) -using BaseWeekInputType = BaseMultipleFieldsDateAndTimeInputType; -#else -using BaseWeekInputType = BaseDateAndTimeInputType; -#endif - -class WeekInputType final : public BaseWeekInputType { +class WeekInputType final : public BaseDateAndTimeInputType { public: static InputType* create(HTMLInputElement&); private: - explicit WeekInputType(HTMLInputElement& element) : BaseWeekInputType(element) { } + explicit WeekInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) {} void countUsage() override; const AtomicString& formControlType() const override;
diff --git a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp index 4dd7cf3..604fa168 100644 --- a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp +++ b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
@@ -30,7 +30,6 @@ #include "core/html/shadow/PickerIndicatorElement.h" -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) #include "core/events/Event.h" #include "core/events/KeyboardEvent.h" #include "core/frame/Settings.h" @@ -190,5 +189,3 @@ } } // namespace blink - -#endif // ENABLE(INPUT_MULTIPLE_FIELDS_UI)
diff --git a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h index 8e150c87..344b36ce 100644 --- a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h +++ b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
@@ -31,9 +31,6 @@ #ifndef PickerIndicatorElement_h #define PickerIndicatorElement_h -#include "wtf/build_config.h" - -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) #include "core/html/HTMLDivElement.h" #include "core/html/forms/DateTimeChooser.h" #include "core/html/forms/DateTimeChooserClient.h" @@ -93,4 +90,3 @@ } // namespace blink #endif -#endif
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h index efdf629..fe0cfc0 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.h +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -74,6 +74,11 @@ LayoutUnit guttersSize(GridTrackSizingDirection, size_t span) const; + LayoutUnit offsetBetweenTracks(GridTrackSizingDirection direction) const + { + return direction == ForColumns ? m_offsetBetweenColumns : m_offsetBetweenRows; + } + typedef Vector<LayoutBox*, 1> GridCell; const GridCell& gridCell(int row, int column) const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp index e5320a0..6f3258c 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
@@ -847,16 +847,15 @@ return false; } -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) bool LayoutTheme::supportsCalendarPicker(const AtomicString& type) const { + DCHECK(RuntimeEnabledFeatures::inputMultipleFieldsUIEnabled()); return type == InputTypeNames::date || type == InputTypeNames::datetime || type == InputTypeNames::datetime_local || type == InputTypeNames::month || type == InputTypeNames::week; } -#endif bool LayoutTheme::shouldUseFallbackTheme(const ComputedStyle&) const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.h b/third_party/WebKit/Source/core/layout/LayoutTheme.h index e09d38f..2d396723 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTheme.h +++ b/third_party/WebKit/Source/core/layout/LayoutTheme.h
@@ -96,10 +96,9 @@ // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const ComputedStyle&) const { return false; } -#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) - // A method asking if the platform is able to show a calendar picker for a given input type. + // A method asking if the platform is able to show a calendar picker for a + // given input type. virtual bool supportsCalendarPicker(const AtomicString&) const; -#endif // Text selection colors. Color activeSelectionBackgroundColor() const;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.cpp index 85d5adb..b53b91a 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.cpp
@@ -36,6 +36,7 @@ : LayoutSVGModelObject(node) , m_objectBoundingBoxValid(false) , m_needsBoundariesUpdate(true) + , m_didTransformToRootUpdate(false) , m_hasNonIsolatedBlendingDescendants(false) , m_hasNonIsolatedBlendingDescendantsDirty(false) { @@ -55,12 +56,11 @@ // Allow LayoutSVGTransformableContainer to update its transform. bool updatedTransform = calculateLocalTransform(); + m_didTransformToRootUpdate = updatedTransform || SVGLayoutSupport::transformToRootChanged(parent()); // LayoutSVGViewportContainer needs to set the 'layout size changed' flag. determineIfLayoutSizeChanged(); - bool transformChanged = SVGLayoutSupport::transformToRootChanged(this); - // When hasRelativeLengths() is false, no descendants have relative lengths // (hence no one is interested in viewport size changes). bool layoutSizeChanged = element()->hasRelativeLengths() @@ -71,7 +71,7 @@ // the descendants. bool forceLayoutOfChildren = selfNeedsLayout() || (normalChildNeedsLayout() && SVGLayoutSupport::hasFilterResource(*this)); - SVGLayoutSupport::layoutChildren(firstChild(), forceLayoutOfChildren, transformChanged, layoutSizeChanged); + SVGLayoutSupport::layoutChildren(firstChild(), forceLayoutOfChildren, m_didTransformToRootUpdate, layoutSizeChanged); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && needsLayout())
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.h index 49caa18..e5c9709 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGContainer.h
@@ -44,7 +44,7 @@ void paint(const PaintInfo&, const LayoutPoint&) const override; void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override; void setNeedsBoundariesUpdate() final { m_needsBoundariesUpdate = true; } - virtual bool didTransformToRootUpdate() const { return false; } + bool didTransformToRootUpdate() const { return m_didTransformToRootUpdate; } bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; } bool selfWillPaint() const; @@ -91,7 +91,8 @@ FloatRect m_objectBoundingBox; FloatRect m_strokeBoundingBox; bool m_objectBoundingBoxValid; - bool m_needsBoundariesUpdate; + bool m_needsBoundariesUpdate : 1; + bool m_didTransformToRootUpdate : 1; mutable bool m_hasNonIsolatedBlendingDescendants : 1; mutable bool m_hasNonIsolatedBlendingDescendantsDirty : 1; };
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp index a29b47c..e27c088 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp
@@ -31,7 +31,6 @@ LayoutSVGTransformableContainer::LayoutSVGTransformableContainer(SVGGraphicsElement* node) : LayoutSVGContainer(node) , m_needsTransformUpdate(true) - , m_didTransformToRootUpdate(false) { } @@ -94,7 +93,6 @@ m_additionalTranslation = translation; } - m_didTransformToRootUpdate = m_needsTransformUpdate || SVGLayoutSupport::transformToRootChanged(parent()); if (!m_needsTransformUpdate) return false;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.h index 6abe13a..2e3868e 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.h
@@ -38,14 +38,12 @@ const FloatSize& additionalTranslation() const { return m_additionalTranslation; } void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } - bool didTransformToRootUpdate() const override { return m_didTransformToRootUpdate; } private: bool calculateLocalTransform() override; AffineTransform localSVGTransform() const override { return m_localTransform; } bool m_needsTransformUpdate : 1; - bool m_didTransformToRootUpdate : 1; AffineTransform m_localTransform; FloatSize m_additionalTranslation; };
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp index 25b9a88..d0d6937 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp
@@ -32,7 +32,6 @@ LayoutSVGViewportContainer::LayoutSVGViewportContainer(SVGElement* node) : LayoutSVGContainer(node) - , m_didTransformToRootUpdate(false) , m_isLayoutSizeChanged(false) , m_needsTransformUpdate(true) { @@ -67,7 +66,6 @@ bool LayoutSVGViewportContainer::calculateLocalTransform() { - m_didTransformToRootUpdate = m_needsTransformUpdate || SVGLayoutSupport::transformToRootChanged(parent()); if (!m_needsTransformUpdate) return false;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h index f223704..545e396 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
@@ -35,7 +35,6 @@ FloatRect viewport() const { return m_viewport; } bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - bool didTransformToRootUpdate() const override { return m_didTransformToRootUpdate; } void determineIfLayoutSizeChanged() override; void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } @@ -57,7 +56,6 @@ FloatRect m_viewport; mutable AffineTransform m_localToParentTransform; - bool m_didTransformToRootUpdate : 1; bool m_isLayoutSizeChanged : 1; bool m_needsTransformUpdate : 1; };
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp index e6c9e2c3..ae3ef656 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -791,7 +791,13 @@ for (const auto& eventTarget : *targets) { EventTarget* target = eventTarget.key; Node* node = target->toNode(); - if (target->toLocalDOMWindow() || node == document || node == document->documentElement() || node == document->body()) { + LocalDOMWindow* window = target->toLocalDOMWindow(); + // If the target is inside a throttled frame, skip it. + if (window && window->frame()->view() && window->frame()->view()->shouldThrottleRendering()) + continue; + if (node && node->document().view() && node->document().view()->shouldThrottleRendering()) + continue; + if (window || node == document || node == document->documentElement() || node == document->body()) { if (LayoutViewItem layoutView = document->layoutViewItem()) { layoutView.computeLayerHitTestRects(rects); } @@ -811,6 +817,10 @@ if (node->document().isInInvisibleSubframe()) continue; + // If the node belongs to a throttled frame, skip it. + if (node->document().view() && node->document().view()->shouldThrottleRendering()) + continue; + if (node->isDocumentNode() && node != document) { accumulateDocumentTouchEventTargetRects(rects, toDocument(node)); } else if (LayoutObject* layoutObject = node->layoutObject()) {
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp index fbc8b05..1ff1f53 100644 --- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp +++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
@@ -42,6 +42,7 @@ #include "bindings/modules/v8/UnionTypesModules.h" #include "bindings/modules/v8/V8RTCCertificate.h" #include "core/dom/DOMException.h" +#include "core/dom/DOMTimeStamp.h" #include "core/dom/Document.h" #include "core/dom/ExceptionCode.h" #include "core/dom/ExecutionContext.h" @@ -88,6 +89,7 @@ #include "public/platform/WebRTCSessionDescriptionRequest.h" #include "public/platform/WebRTCStatsRequest.h" #include "public/platform/WebRTCVoidRequest.h" +#include "wtf/CurrentTime.h" #include <memory> @@ -321,7 +323,6 @@ rtcConfiguration->appendCertificate(certificate->certificateShallowCopy()); } } - return rtcConfiguration; } @@ -388,6 +389,18 @@ if (exceptionState.hadException()) return 0; + // Make sure no certificates have expired. + if (configuration && configuration->numberOfCertificates() > 0) { + DOMTimeStamp now = convertSecondsToDOMTimeStamp(currentTime()); + for (size_t i = 0; i < configuration->numberOfCertificates(); ++i) { + DOMTimeStamp expires = configuration->certificate(i)->expires(); + if (expires <= now) { + exceptionState.throwDOMException(InvalidStateError, "Expired certificate(s)."); + return 0; + } + } + } + MediaErrorState mediaErrorState; WebMediaConstraints constraints = MediaConstraintsImpl::create(context, mediaConstraints, mediaErrorState); if (mediaErrorState.hadException()) {
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h index bd4ac8ae..b04bbf0a 100644 --- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h +++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
@@ -70,7 +70,6 @@ USING_GARBAGE_COLLECTED_MIXIN(RTCPeerConnection); USING_PRE_FINALIZER(RTCPeerConnection, dispose); public: - // TODO(hbos): Create with expired RTCCertificate should fail, see crbug.com/565278. static RTCPeerConnection* create(ExecutionContext*, const Dictionary&, const Dictionary&, ExceptionState&); ~RTCPeerConnection() override;
diff --git a/third_party/WebKit/Source/modules/notifications/OWNERS b/third_party/WebKit/Source/modules/notifications/OWNERS index 2fca67fd..6ce739c6 100644 --- a/third_party/WebKit/Source/modules/notifications/OWNERS +++ b/third_party/WebKit/Source/modules/notifications/OWNERS
@@ -1 +1,2 @@ +mvanouwerkerk@chromium.org peter@chromium.org \ No newline at end of file
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h index 91dc1703..1bcfc82 100644 --- a/third_party/WebKit/Source/platform/heap/HeapPage.h +++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -142,7 +142,7 @@ // - 1 bit used to mark DOM trees for V8. // - 14 bit is enough for gcInfoIndex because there are less than 2^14 types // in Blink. -const size_t headerDOMMarkBitMask = 1u << 17; +const size_t headerWrapperMarkBitMask = 1u << 17; const size_t headerGCInfoIndexShift = 18; const size_t headerGCInfoIndexMask = (static_cast<size_t>((1 << 14) - 1)) << headerGCInfoIndexShift; const size_t headerSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3; @@ -205,6 +205,9 @@ ASSERT(size < nonLargeObjectPageSizeMax); m_encoded = static_cast<uint32_t>(size) | (m_encoded & ~headerSizeMask); } + bool isWrapperHeaderMarked() const; + void markWrapperHeader(); + void unmarkWrapperHeader(); bool isMarked() const; void mark(); void unmark(); @@ -835,6 +838,29 @@ } NO_SANITIZE_ADDRESS inline +bool HeapObjectHeader::isWrapperHeaderMarked() const +{ + ASSERT(checkHeader()); + return m_encoded & headerWrapperMarkBitMask; +} + +NO_SANITIZE_ADDRESS inline +void HeapObjectHeader::markWrapperHeader() +{ + ASSERT(checkHeader()); + ASSERT(!isWrapperHeaderMarked()); + m_encoded |= headerWrapperMarkBitMask; +} + +NO_SANITIZE_ADDRESS inline +void HeapObjectHeader::unmarkWrapperHeader() +{ + ASSERT(checkHeader()); + ASSERT(isWrapperHeaderMarked()); + m_encoded &= ~headerWrapperMarkBitMask; +} + +NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::isMarked() const { ASSERT(checkHeader());
diff --git a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp index 3353b15..60faa0b8 100644 --- a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp +++ b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
@@ -8,8 +8,10 @@ #include "core/html/HTMLIFrameElement.h" #include "core/page/FocusController.h" #include "core/page/Page.h" +#include "core/paint/PaintLayer.h" #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" +#include "public/platform/WebLayer.h" #include "public/web/WebHitTestResult.h" #include "public/web/WebSettings.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,6 +42,12 @@ testing::runPendingTasks(); return displayItems; } + + // Number of rectangles that make up the root layer's touch handler region. + size_t touchHandlerRegionSize() + { + return webView().mainFrameImpl()->frame()->contentLayoutItem().layer()->graphicsLayerBacking()->platformLayer()->touchEventHandlerRegion().size(); + } }; TEST_F(FrameThrottlingTest, ThrottleInvisibleFrames) @@ -546,4 +554,71 @@ EXPECT_FALSE(frameElement->contentDocument()->view()->canThrottleRendering()); } +TEST_F(FrameThrottlingTest, ThrottledTopLevelEventHandlerIgnored) +{ + webView().settings()->setAcceleratedCompositingEnabled(true); + webView().settings()->setJavaScriptEnabled(true); + EXPECT_EQ(0u, touchHandlerRegionSize()); + + // Create a frame which is throttled and has two different types of + // top-level touchstart handlers. + SimRequest mainResource("https://example.com/", "text/html"); + SimRequest frameResource("https://example.com/iframe.html", "text/html"); + + loadURL("https://example.com/"); + mainResource.complete("<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>"); + frameResource.complete( + "<script>" + "window.addEventListener('touchstart', function(){});" + "document.addEventListener('touchstart', function(){});" + "</script>"); + auto* frameElement = toHTMLIFrameElement(document().getElementById("frame")); + frameElement->setAttribute(styleAttr, "transform: translateY(480px)"); + compositeFrame(); // Throttle the frame. + compositeFrame(); // Update touch handler regions. + + // The touch handlers in the throttled frame should have been ignored. + EXPECT_EQ(0u, touchHandlerRegionSize()); + + // Unthrottling the frame makes the touch handlers active again. Note that + // both handlers get combined into the same rectangle in the region, so + // there is only one rectangle in total. + frameElement->setAttribute(styleAttr, "transform: translateY(0px)"); + compositeFrame(); // Unthrottle the frame. + compositeFrame(); // Update touch handler regions. + EXPECT_EQ(1u, touchHandlerRegionSize()); +} + +TEST_F(FrameThrottlingTest, ThrottledEventHandlerIgnored) +{ + webView().settings()->setAcceleratedCompositingEnabled(true); + webView().settings()->setJavaScriptEnabled(true); + EXPECT_EQ(0u, touchHandlerRegionSize()); + + // Create a frame which is throttled and has a non-top-level touchstart handler. + SimRequest mainResource("https://example.com/", "text/html"); + SimRequest frameResource("https://example.com/iframe.html", "text/html"); + + loadURL("https://example.com/"); + mainResource.complete("<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>"); + frameResource.complete( + "<div id=d>touch handler</div>" + "<script>" + "document.querySelector('#d').addEventListener('touchstart', function(){});" + "</script>"); + auto* frameElement = toHTMLIFrameElement(document().getElementById("frame")); + frameElement->setAttribute(styleAttr, "transform: translateY(480px)"); + compositeFrame(); // Throttle the frame. + compositeFrame(); // Update touch handler regions. + + // The touch handler in the throttled frame should have been ignored. + EXPECT_EQ(0u, touchHandlerRegionSize()); + + // Unthrottling the frame makes the touch handler active again. + frameElement->setAttribute(styleAttr, "transform: translateY(0px)"); + compositeFrame(); // Unthrottle the frame. + compositeFrame(); // Update touch handler regions. + EXPECT_EQ(1u, touchHandlerRegionSize()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp index 805e58a2c..af01507 100644 --- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -2067,7 +2067,13 @@ webView->handleInputEvent(keyEvent); } -TEST_F(WebViewTest, ChooseValueFromDateTimeChooser) +// TODO(crbug.com/605112) This test is crashing on Android (Nexus 4) bot. +#if OS(ANDROID) +#define MAYBE_ChooseValueFromDateTimeChooser DISABLED_ChooseValueFromDateTimeChooser +#else +#define MAYBE_ChooseValueFromDateTimeChooser ChooseValueFromDateTimeChooser +#endif +TEST_F(WebViewTest, MAYBE_ChooseValueFromDateTimeChooser) { DateTimeChooserWebViewClient client; std::string url = m_baseURL + "date_time_chooser.html";
diff --git a/third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp b/third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp index 8546387..12c9a7b 100644 --- a/third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp +++ b/third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp
@@ -31,6 +31,7 @@ #include "wtf/allocator/PageAllocator.h" #include "wtf/Assertions.h" +#include "wtf/Atomics.h" #include "wtf/allocator/AddressSpaceRandomization.h" #include <limits.h> @@ -50,7 +51,7 @@ // On POSIX memmap uses a nearby address if the hint address is blocked. static const bool kHintIsAdvisory = true; -static uint32_t allocPageErrorCode = 0; +static uint32_t s_allocPageErrorCode = 0; #elif OS(WIN) @@ -58,7 +59,7 @@ // VirtualAlloc will fail if allocation at the hint address is blocked. static const bool kHintIsAdvisory = false; -static uint32_t allocPageErrorCode = ERROR_SUCCESS; +static uint32_t s_allocPageErrorCode = ERROR_SUCCESS; #else #error Unknown OS @@ -80,12 +81,12 @@ DWORD accessFlag = pageAccessibility == PageAccessible ? PAGE_READWRITE : PAGE_NOACCESS; ret = VirtualAlloc(hint, len, MEM_RESERVE | MEM_COMMIT, accessFlag); if (!ret) - allocPageErrorCode = GetLastError(); + releaseStore(&s_allocPageErrorCode, GetLastError()); #else int accessFlag = pageAccessibility == PageAccessible ? (PROT_READ | PROT_WRITE) : PROT_NONE; ret = mmap(hint, len, accessFlag, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (ret == MAP_FAILED) { - allocPageErrorCode = errno; + releaseStore(&s_allocPageErrorCode, errno); ret = 0; } #endif @@ -270,7 +271,7 @@ uint32_t getAllocPageErrorCode() { - return allocPageErrorCode; + return acquireLoad(&s_allocPageErrorCode); } } // namespace WTF
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium index 7b993a1..558808a 100644 --- a/third_party/libjingle/README.chromium +++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@ Name: libjingle URL: http://www.webrtc.org Version: unknown -Revision: 12291 +Revision: 12410 License: BSD License File: source/talk/COPYING Security Critical: yes
diff --git a/third_party/woff2/README.chromium b/third_party/woff2/README.chromium index 70deff2e..e45a118 100644 --- a/third_party/woff2/README.chromium +++ b/third_party/woff2/README.chromium
@@ -14,3 +14,6 @@ - BUILD.gn: Added. - woff2.gyp: Added. - src/port.h: Include <assert.h>. +- src/woff2_dec.cc: Msan error fix. + +Changes under src/ will be fixed in the upstream repository soon.
diff --git a/third_party/woff2/src/woff2_dec.cc b/third_party/woff2/src/woff2_dec.cc index 837eede1..ea1f1693 100644 --- a/third_party/woff2/src/woff2_dec.cc +++ b/third_party/woff2/src/woff2_dec.cc
@@ -603,13 +603,12 @@ *glyf_checksum += ComputeULongSum(glyph_buf.get(), glyph_size); // We may need x_min to reconstruct 'hmtx' - Buffer x_min_buf(glyph_buf.get() + 2, 2); - int16_t x_min; - if (PREDICT_FALSE(!x_min_buf.ReadS16(&x_min))) { - return FONT_COMPRESSION_FAILURE(); + if (n_contours > 0) { + Buffer x_min_buf(glyph_buf.get() + 2, 2); + if (PREDICT_FALSE(!x_min_buf.ReadS16(&info->x_mins[i]))) { + return FONT_COMPRESSION_FAILURE(); + } } - - info->x_mins[i] = n_contours != 0 ? x_min : 0; } // glyf_table dst_offset was set by ReconstructFont
diff --git a/tools/android/loading/chrome_cache.py b/tools/android/loading/chrome_cache.py index 9d486e9c..4c1f226 100644 --- a/tools/android/loading/chrome_cache.py +++ b/tools/android/loading/chrome_cache.py
@@ -219,7 +219,11 @@ f.write(zip_input.read(file_archive_name)) assert timestamps - for relative_path, stats in timestamps.iteritems(): + # os.utime(file_path, ...) modifies modification time of file_path's parent + # directories. Therefore we call os.utime on files and directories that have + # longer relative paths first. + for relative_path in sorted(timestamps.keys(), key=len, reverse=True): + stats = timestamps[relative_path] output_path = os.path.join(directory_dest_path, relative_path) if not os.path.exists(output_path): os.makedirs(output_path)
diff --git a/tools/android/loading/cloud/backend/README.md b/tools/android/loading/cloud/backend/README.md index 5f534f22..b181cfa9 100644 --- a/tools/android/loading/cloud/backend/README.md +++ b/tools/android/loading/cloud/backend/README.md
@@ -95,15 +95,21 @@ https://www.googleapis.com/auth/cloud-platform ``` -Create a JSON file describing the deployment configuration: +Create a JSON dictionary file describing the deployment configuration, with the +keys: +- `project_name` (string): Name of the Google Cloud project +- `cloud_storage_path` (string): Path in Google Storage where generated traces + will be stored. +- `chrome_path` (string): Path to the Chrome executable. +- `src_path` (string): Path to the Chromium source directory. +- `taskqueue_tag` (string): +- `trace_database_filename` (string, optional): Filename for the trace + database in Cloud Storage. Must be unique per worker to avoid concurrent + access. Defaults to `trace_database.json`. + +Example: ```shell -# CONFIG_FILE is the output json file. -# PROJECT_NAME is the Google Cloud project. -# CLOUD_STORAGE_PATH is the path in Google Storage where generated traces will -# be stored. -# CHROME_PATH is the path to the Chrome executable on the host. -# CHROMIUM_SRC is the Chromium src directory. cat >$CONFIG_FILE << EOF { "project_name" : "$PROJECT_NAME",
diff --git a/tools/android/loading/cloud/backend/google_storage_accessor.py b/tools/android/loading/cloud/backend/google_storage_accessor.py index 86e238e8..ded3fe8 100644 --- a/tools/android/loading/cloud/backend/google_storage_accessor.py +++ b/tools/android/loading/cloud/backend/google_storage_accessor.py
@@ -2,7 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -from gcloud import storage +import gcloud.exceptions +import gcloud.storage class GoogleStorageAccessor(object): @@ -18,12 +19,26 @@ def _GetStorageClient(self): """Returns the storage client associated with the project""" - return storage.Client(project = self._project_name, - credentials = self._credentials) + return gcloud.storage.Client(project = self._project_name, + credentials = self._credentials) def _GetStorageBucket(self, storage_client): return storage_client.get_bucket(self._bucket_name) + def DownloadAsString(self, remote_filename): + """Returns the content of a remote file as a string, or None if the file + does not exist. + """ + client = self._GetStorageClient() + bucket = self._GetStorageBucket(client) + blob = bucket.get_blob(remote_filename) + if not blob: + return None + try: + return blob.download_as_string() + except gcloud.exceptions.NotFound: + return None + def UploadFile(self, filename_src, filename_dest): """Uploads a file to Google Cloud Storage
diff --git a/tools/android/loading/cloud/backend/startup-script.sh b/tools/android/loading/cloud/backend/startup-script.sh index e429c1e..3d3084f0 100644 --- a/tools/android/loading/cloud/backend/startup-script.sh +++ b/tools/android/loading/cloud/backend/startup-script.sh
@@ -12,11 +12,15 @@ -H "Metadata-Flavor: Google" } -# Talk to the metadata server to get the project id +# Talk to the metadata server to get the project id and the instance id PROJECTID=$(curl -s \ "http://metadata.google.internal/computeMetadata/v1/project/project-id" \ -H "Metadata-Flavor: Google") +INSTANCE_ID=$(curl -s \ + "http://metadata.google.internal/computeMetadata/v1/instance/hostname" \ + -H "Metadata-Flavor: Google") + # Install dependencies from apt apt-get update # Basic dependencies @@ -73,7 +77,8 @@ "cloud_storage_path" : "$CLOUD_STORAGE_PATH", "chrome_path" : "/opt/app/clovis/binaries/chrome", "src_path" : "/opt/app/clovis/src", - "taskqueue_tag" : "$TASKQUEUE_TAG" + "taskqueue_tag" : "$TASKQUEUE_TAG", + "trace_database_filename" : "trace_database_${INSTANCE_ID}.json" } EOF
diff --git a/tools/android/loading/cloud/backend/worker.py b/tools/android/loading/cloud/backend/worker.py index b9900cec..9518171 100644 --- a/tools/android/loading/cloud/backend/worker.py +++ b/tools/android/loading/cloud/backend/worker.py
@@ -32,6 +32,7 @@ """See README.md for the config format.""" self._project_name = config['project_name'] self._taskqueue_tag = config['taskqueue_tag'] + self._src_path = config['src_path'] self._credentials = GoogleCredentials.get_application_default() self._logger = logger @@ -45,15 +46,18 @@ if not self._base_path_in_bucket.endswith('/'): self._base_path_in_bucket += '/' - # TODO: improve the trace database to support concurrent access. - self._traces_dir = self._base_path_in_bucket + 'traces/' - self._trace_database = LoadingTraceDatabase({}) - - self._src_path = config['src_path'] self._google_storage_accessor = GoogleStorageAccessor( credentials=self._credentials, project_name=self._project_name, bucket_name=self._bucket_name) + self._traces_dir = os.path.join(self._base_path_in_bucket, 'traces') + self._trace_database_path = os.path.join( + self._traces_dir, + config.get('trace_database_filename', 'trace_database.json')) + + # Recover any existing trace database in case the worker died. + self._DownloadTraceDatabase() + # Initialize the global options that will be used during trace generation. options.OPTIONS.ParseArgs([]) options.OPTIONS.local_binary = config['chrome_path'] @@ -94,6 +98,21 @@ self._logger.info('Finished task %s' % task_id) self._Finalize() + def _DownloadTraceDatabase(self): + """Downloads the trace database from CloudStorage.""" + self._logger.info('Downloading trace database') + trace_database_string = self._google_storage_accessor.DownloadAsString( + self._trace_database_path) or '{}' + trace_database_dict = json.loads(trace_database_string) + self._trace_database = LoadingTraceDatabase(trace_database_dict) + + def _UploadTraceDatabase(self): + """Uploads the trace database to CloudStorage.""" + self._logger.info('Uploading trace database') + self._google_storage_accessor.UploadString( + json.dumps(self._trace_database.ToJsonDict(), indent=2), + self._trace_database_path) + def _FetchClovisTask(self, project_name, task_api, queue_name): """Fetches a ClovisTask from the task queue. @@ -119,14 +138,9 @@ def _Finalize(self): """Called before exiting.""" - self._logger.info('Uploading trace database') - self._google_storage_accessor.UploadString( - json.dumps(self._trace_database.ToJsonDict(), indent=2), - self._traces_dir + 'trace_database.json') # TODO(droger): Implement automatic instance destruction. self._logger.info('Done') - def _GenerateTrace(self, url, emulate_device, emulate_network, filename, log_filename): """ Generates a trace. @@ -201,9 +215,9 @@ emulate_device = params.get('emulate_device') emulate_network = params.get('emulate_network') - failures_dir = self._base_path_in_bucket + 'failures/' + failures_dir = os.path.join(self._base_path_in_bucket, 'failures') # TODO(blundell): Fix this up. - logs_dir = self._base_path_in_bucket + 'analyze_logs/' + logs_dir = os.path.join(self._base_path_in_bucket, 'analyze_logs') log_filename = 'analyze.log' # Avoid special characters in storage object names pattern = re.compile(r"[#\?\[\]\*/]") @@ -213,27 +227,27 @@ local_filename = pattern.sub('_', url) for repeat in range(repeat_count): self._logger.debug('Generating trace for URL: %s' % url) - remote_filename = local_filename + '/' + str(repeat) + remote_filename = os.path.join(local_filename, str(repeat)) trace_metadata = self._GenerateTrace( url, emulate_device, emulate_network, local_filename, log_filename) if trace_metadata['succeeded']: self._logger.debug('Uploading: %s' % remote_filename) - remote_trace_location = self._traces_dir + remote_filename + remote_trace_location = os.path.join(self._traces_dir, + remote_filename) self._google_storage_accessor.UploadFile(local_filename, remote_trace_location) - full_cloud_storage_path = ('gs://' + self._bucket_name + '/' + - remote_trace_location) - self._trace_database.AddTrace(full_cloud_storage_path, trace_metadata) + full_cloud_storage_path = os.path.join('gs://' + self._bucket_name, + remote_trace_location) + self._trace_database.SetTrace(full_cloud_storage_path, trace_metadata) else: self._logger.warning('Trace generation failed for URL: %s' % url) - # TODO: upload the failure if os.path.isfile(local_filename): - self._google_storage_accessor.UploadFile(local_filename, - failures_dir + remote_filename) - self._logger.debug('Uploading log') - self._google_storage_accessor.UploadFile(log_filename, - logs_dir + remote_filename) - + self._google_storage_accessor.UploadFile( + local_filename, os.path.join(failures_dir, remote_filename)) + self._logger.debug('Uploading analyze log') + self._google_storage_accessor.UploadFile( + log_filename, os.path.join(logs_dir, remote_filename)) + self._UploadTraceDatabase() if __name__ == '__main__': parser = argparse.ArgumentParser(
diff --git a/tools/android/loading/loading_trace_database.py b/tools/android/loading/loading_trace_database.py index 2ef33b0..dad6153 100644 --- a/tools/android/loading/loading_trace_database.py +++ b/tools/android/loading/loading_trace_database.py
@@ -14,9 +14,10 @@ about those traces.""" self._traces_dict = traces_dict - def AddTrace(self, filename, trace_dict): - """Adds a mapping from |filename| to |trace_dict| into the database.""" - assert filename not in self._traces_dict + def SetTrace(self, filename, trace_dict): + """Sets a mapping from |filename| to |trace_dict| into the database. + If there is an existing mapping for filename, it is replaced. + """ self._traces_dict[filename] = trace_dict def GetTraceFilesForURL(self, url):
diff --git a/tools/android/loading/loading_trace_database_unittest.py b/tools/android/loading/loading_trace_database_unittest.py index 31dc9b3..e64fb8c 100644 --- a/tools/android/loading/loading_trace_database_unittest.py +++ b/tools/android/loading/loading_trace_database_unittest.py
@@ -32,11 +32,11 @@ self.assertEqual( self._JSON_DATABASE, self.database.ToJsonDict()) - def testAddTrace(self): + def testSetTrace(self): dummy_url = "http://dummy.com" new_trace_file = "traces/new_trace.json" self.assertEqual(self.database.GetTraceFilesForURL(dummy_url), []) - self.database.AddTrace(new_trace_file, {"url" : dummy_url}) + self.database.SetTrace(new_trace_file, {"url" : dummy_url}) self.assertEqual(self.database.GetTraceFilesForURL(dummy_url), [new_trace_file])
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py index bf19fbbf..9f513d2e 100644 --- a/tools/android/loading/request_track.py +++ b/tools/android/loading/request_track.py
@@ -25,7 +25,8 @@ 'requestTime': 'request_time', 'sendEnd': 'send_end', 'sendStart': 'send_start', 'sslEnd': 'ssl_end', 'sslStart': 'ssl_start', 'workerReady': 'worker_ready', 'workerStart': 'worker_start', - 'loadingFinished': 'loading_finished'} + 'loadingFinished': 'loading_finished', 'pushStart' : 'push_start', + 'pushEnd' : 'push_end'} Timing = collections.namedtuple('Timing', _TIMING_NAMES_MAPPING.values())
diff --git a/tools/copyright_scanner/third_party_files_whitelist.txt b/tools/copyright_scanner/third_party_files_whitelist.txt index 43fc331..91def808 100644 --- a/tools/copyright_scanner/third_party_files_whitelist.txt +++ b/tools/copyright_scanner/third_party_files_whitelist.txt
@@ -174,9 +174,6 @@ # third-party code is taken from Mozilla, the license for which we already pick # up from third_party/npapi/. net/proxy/proxy_resolver_script.h -# Copyright The Chromium Authors and Netscape Communications Corporation; BSD -# and (MPL, GPL v2 or LGPL v2) licenses. Not used on Android. -net/socket/ssl_client_socket_nss.cc # Contains the word 'Copyright' in comments ppapi/generators/idl_c_proto.py ppapi/generators/idl_outfile.py
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn index 2728c0d..bb36b1ff 100644 --- a/tools/gn/BUILD.gn +++ b/tools/gn/BUILD.gn
@@ -277,7 +277,6 @@ "function_write_file_unittest.cc", "functions_target_unittest.cc", "functions_unittest.cc", - "group_target_generator_unittest.cc", "header_checker_unittest.cc", "inherited_libraries_unittest.cc", "input_conversion_unittest.cc",
diff --git a/tools/gn/docs/cookbook.md b/tools/gn/docs/cookbook.md index febc16c..92bfeb55 100644 --- a/tools/gn/docs/cookbook.md +++ b/tools/gn/docs/cookbook.md
@@ -279,8 +279,6 @@ | `use_gnome_keyring` (0/1) | `is_desktop_linux` (true/false) | | | `use_goma` (0/1) | `use_goma` (true/false) | `//build/toolchain/goma.gni` | | `use_nss_certs` (0/1) | `use_nss_certs` (true/false) | `//build/config/crypto.gni` (Many of these conditions can be deleted, see the "SSL" notes on targets below.) | -| `use_nss_verifier` (0/1) | `use_nss_verifier` (true/false) | `//build/config/crypto.gni` (Many of these conditions can be deleted, see the "SSL" notes on targets below.) | -| `use_openssl` (0/1) | `use_openssl` (true/false) | `//build/config/crypto.gni` (Many of these conditions can be deleted, see the "SSL" notes on targets below.) | | `use_pango` (0/1) | `use_pango` (true/false) | `//build/config/ui.gni` | | `use_ozone` (0/1) | `use_ozone` (true/false) | `//build/config/ui.gni` | | `use_seccomp_bpf` (0/1) | `use_seccomp_bpf` (true/false) | `//build/config/features.gni` |
diff --git a/tools/gn/group_target_generator_unittest.cc b/tools/gn/group_target_generator_unittest.cc deleted file mode 100644 index 3b0c824..0000000 --- a/tools/gn/group_target_generator_unittest.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2016 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 "testing/gtest/include/gtest/gtest.h" -#include "tools/gn/group_target_generator.h" -#include "tools/gn/scheduler.h" -#include "tools/gn/test_with_scope.h" - -namespace { - -// Returns true on success, false if write_file signaled an error. -bool ParseWriteRuntimeDeps(Scope* scope, const std::string& value) { - TestParseInput input( - "group(\"foo\") { write_runtime_deps = " + value + "}"); - if (input.has_error()) - return false; - - Err err; - input.parsed()->Execute(scope, &err); - return !err.has_error(); -} - -} // namespace - - -// Tests that actions can't have output substitutions. -TEST(GroupTargetGenerator, WriteRuntimeDeps) { - Scheduler scheduler; - TestWithScope setup; - Scope::ItemVector items_; - setup.scope()->set_item_collector(&items_); - - // Should refuse to write files outside of the output dir. - EXPECT_FALSE(ParseWriteRuntimeDeps(setup.scope(), "\"//foo.txt\"")); - EXPECT_EQ(0U, scheduler.GetWriteRuntimeDepsTargets().size()); - - // Should fail for garbage inputs. - EXPECT_FALSE(ParseWriteRuntimeDeps(setup.scope(), "0")); - EXPECT_EQ(0U, scheduler.GetWriteRuntimeDepsTargets().size()); - - // Should be able to write inside the out dir. - EXPECT_TRUE(ParseWriteRuntimeDeps(setup.scope(), "\"//out/Debug/foo.txt\"")); - EXPECT_EQ(1U, scheduler.GetWriteRuntimeDepsTargets().size()); -} -
diff --git a/tools/gn/runtime_deps_unittest.cc b/tools/gn/runtime_deps_unittest.cc index 915fbc2..6c2013d 100644 --- a/tools/gn/runtime_deps_unittest.cc +++ b/tools/gn/runtime_deps_unittest.cc
@@ -8,6 +8,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/runtime_deps.h" +#include "tools/gn/scheduler.h" #include "tools/gn/target.h" #include "tools/gn/test_with_scope.h" @@ -282,3 +283,31 @@ MakePair("../../action.output", &action)) != result.end()) << GetVectorDescription(result); } + +// Tests that actions can't have output substitutions. +TEST(RuntimeDeps, WriteRuntimeDepsVariable) { + Scheduler scheduler; + TestWithScope setup; + Err err; + + // Should refuse to write files outside of the output dir. + EXPECT_FALSE(setup.ExecuteSnippet( + "group(\"foo\") { write_runtime_deps = \"//foo.txt\" }", &err)); + + // Should fail for garbage inputs. + err = Err(); + EXPECT_FALSE(setup.ExecuteSnippet( + "group(\"foo\") { write_runtime_deps = 0 }", &err)); + + // Should be able to write inside the out dir, and shouldn't write the one + // in the else clause. + err = Err(); + EXPECT_TRUE(setup.ExecuteSnippet( + "if (true) {\n" + " group(\"foo\") { write_runtime_deps = \"//out/Debug/foo.txt\" }\n" + "} else {\n" + " group(\"bar\") { write_runtime_deps = \"//out/Debug/bar.txt\" }\n" + "}", &err)); + EXPECT_EQ(1U, setup.items().size()); + EXPECT_EQ(1U, scheduler.GetWriteRuntimeDepsTargets().size()); +}
diff --git a/tools/gn/target.cc b/tools/gn/target.cc index 18c353e..e88c82f 100644 --- a/tools/gn/target.cc +++ b/tools/gn/target.cc
@@ -324,6 +324,9 @@ CheckSourcesGenerated(); } + if (!write_runtime_deps_output_.value().empty()) + g_scheduler->AddWriteRuntimeDepsTarget(this); + return true; }
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc index 2132a5b..90642d4 100644 --- a/tools/gn/target_generator.cc +++ b/tools/gn/target_generator.cc
@@ -403,6 +403,5 @@ OutputFile output_file(GetBuildSettings(), source_file); target_->set_write_runtime_deps_output(output_file); - g_scheduler->AddWriteRuntimeDepsTarget(target_); return true; }
diff --git a/tools/gn/test_with_scope.cc b/tools/gn/test_with_scope.cc index 32d5dd6..0ddd463 100644 --- a/tools/gn/test_with_scope.cc +++ b/tools/gn/test_with_scope.cc
@@ -24,6 +24,7 @@ settings_.set_default_toolchain_label(toolchain_.label()); SetupToolchain(&toolchain_); + scope_.set_item_collector(&items_); } TestWithScope::~TestWithScope() { @@ -37,6 +38,28 @@ return result; } +bool TestWithScope::ExecuteSnippet(const std::string& str, Err* err) { + TestParseInput input(str); + if (input.has_error()) { + *err = input.parse_err(); + return false; + } + + size_t first_item = items_.size(); + input.parsed()->Execute(&scope_, err); + if (err->has_error()) + return false; + + for (size_t i = first_item; i < items_.size(); ++i) { + CHECK(items_[i]->AsTarget() != nullptr) + << "Only targets are supported in ExecuteSnippet()"; + items_[i]->AsTarget()->SetToolchain(&toolchain_); + if (!items_[i]->OnResolved(err)) + return false; + } + return true; +} + // static void TestWithScope::SetupToolchain(Toolchain* toolchain) { Err err;
diff --git a/tools/gn/test_with_scope.h b/tools/gn/test_with_scope.h index fa6fb4b..8853243 100644 --- a/tools/gn/test_with_scope.h +++ b/tools/gn/test_with_scope.h
@@ -34,6 +34,7 @@ Toolchain* toolchain() { return &toolchain_; } const Toolchain* toolchain() const { return &toolchain_; } Scope* scope() { return &scope_; } + const Scope::ItemVector& items() { return items_; } // This buffer accumulates output from any print() commands executed in the // context of this test. Note that the implementation of this is not @@ -44,6 +45,11 @@ // assert if the label isn't valid (this is intended for hardcoded labels). Label ParseLabel(const std::string& str) const; + // Parses, evaluates, and resolves targets from the given snippet of code. + // All targets must be defined in dependency order (does not use a Builder, + // just blindly resolves all targets in order). + bool ExecuteSnippet(const std::string& str, Err* err); + // Fills in the tools for the given toolchain with reasonable default values. // The toolchain in this object will be automatically set up with this // function, it is exposed to allow tests to get the same functionality for @@ -62,6 +68,7 @@ Settings settings_; Toolchain toolchain_; Scope scope_; + Scope::ItemVector items_; // Supplies the scope with built-in variables like root_out_dir. ScopePerFileProvider scope_progammatic_provider_;
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni index 90c0b00..07d8f3a 100644 --- a/tools/grit/grit_rule.gni +++ b/tools/grit/grit_rule.gni
@@ -159,13 +159,6 @@ ] } -if (use_nss_verifier) { - grit_defines += [ - "-D", - "use_nss_verifier", - ] -} - if (use_ozone) { grit_defines += [ "-D",
diff --git a/tools/idl_parser/OWNERS b/tools/idl_parser/OWNERS new file mode 100644 index 0000000..c5e87c09 --- /dev/null +++ b/tools/idl_parser/OWNERS
@@ -0,0 +1,3 @@ +bashi@chromium.org +haraken@chromium.org +yukishiino@chromium.org
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py index 45f8d7c..ff787a46 100755 --- a/tools/idl_parser/idl_parser.py +++ b/tools/idl_parser/idl_parser.py
@@ -554,14 +554,12 @@ # [36] def p_StringifierRest(self, p): - """StringifierRest : AttributeRest + """StringifierRest : ReadOnly AttributeRest | ReturnType OperationRest | ';'""" if len(p) == 3: p[2].AddChildren(p[1]) p[0] = p[2] - elif p[1] != ';': - p[0] = p[1] # [37] def p_StaticMember(self, p):
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 91cbf8a9..80ab100 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -5428,6 +5428,23 @@ </summary> </histogram> +<histogram name="Compositing.Browser.NumActiveLayers" units="layers"> + <owner>paint-dev@chromium.org</owner> + <summary> + The number of layers in the active tree for each compositor frame. This is + logged once per frame, before the frame is drawn (in a browser process). + </summary> +</histogram> + +<histogram name="Compositing.Browser.NumRenderSurfaces" units="surfaces"> + <owner>paint-dev@chromium.org</owner> + <summary> + The number of render surfaces in the render surface layer list. Recorded + each time the render surface layer list is constructed (in a browser + process). + </summary> +</histogram> + <histogram name="Compositing.Browser.PictureMemoryUsageKb" units="KB"> <owner>paint-dev@chromium.org</owner> <summary> @@ -5540,6 +5557,10 @@ </histogram> <histogram name="Compositing.NumActiveLayers"> + <obsolete> + Deprecated 04/2016, replaced by similar metrics under Compositing.Renderer + and Compositing.Browser, depending on which process it occurs in. + </obsolete> <owner>dneto@chromium.org</owner> <summary> The number of layers in the active tree for each compositor frame. This is @@ -5646,6 +5667,23 @@ </summary> </histogram> +<histogram name="Compositing.Renderer.NumActiveLayers" units="layers"> + <owner>paint-dev@chromium.org</owner> + <summary> + The number of layers in the active tree for each compositor frame. This is + logged once per frame, before the frame is drawn (in a renderer process). + </summary> +</histogram> + +<histogram name="Compositing.Renderer.NumRenderSurfaces" units="surfaces"> + <owner>paint-dev@chromium.org</owner> + <summary> + The number of render surfaces in the render surface layer list. Recorded + each time the render surface layer list is constructed (in a renderer + process). + </summary> +</histogram> + <histogram name="Compositing.Renderer.PictureMemoryUsageKb" units="KB"> <owner>paint-dev@chromium.org</owner> <summary> @@ -75647,6 +75685,7 @@ <int value="-384589459" label="disable-supervised-user-safesites"/> <int value="-378180863" label="disable-panels"/> <int value="-378033324" label="disable-win32k-renderer-lockdown"/> + <int value="-362022976" label="disable-quirks-client"/> <int value="-360038744" label="invert-viewport-scroll-order"/> <int value="-351552989" label="disable-hosted-apps-in-windows"/> <int value="-351127770" label="enable-offline-pages-as-bookmarks"/>
diff --git a/tools/perf/benchmarks/memory_infra.py b/tools/perf/benchmarks/memory_infra.py index 801dd47..40f09ad 100644 --- a/tools/perf/benchmarks/memory_infra.py +++ b/tools/perf/benchmarks/memory_infra.py
@@ -52,22 +52,13 @@ # TODO(bashi): Workaround for http://crbug.com/532075 # @benchmark.Enabled('android') shouldn't be needed. @benchmark.Enabled('android') -class MemoryHealthPlan(_MemoryInfra): - """Timeline based benchmark for the Memory Health Plan.""" - - _PREFIX_WHITELIST = ('memory_allocator_', 'memory_android_memtrack_', - 'memory_mmaps_', 'process_count_') - +class MemoryHealthQuick(_MemoryInfra): + """Timeline based benchmark for the Memory Health Plan (1 iteration).""" page_set = page_sets.MemoryHealthStory @classmethod def Name(cls): - return 'memory.memory_health_plan' - - @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - return (value.tir_label in ['foreground', 'background'] - and any(value.name.startswith(p) for p in cls._PREFIX_WHITELIST)) + return 'memory.memory_health_quick' @classmethod def ShouldDisable(cls, possible_browser): @@ -76,6 +67,17 @@ return 'nexus' not in possible_browser.platform.GetDeviceTypeName().lower() +# Benchmark is disabled by default because it takes too long to run. +@benchmark.Disabled('all') +class MemoryHealthPlan(MemoryHealthQuick): + """Timeline based benchmark for the Memory Health Plan (5 iterations).""" + options = {'pageset_repeat': 5} + + @classmethod + def Name(cls): + return 'memory.memory_health_plan' + + # TODO(bashi): Workaround for http://crbug.com/532075 # @benchmark.Enabled('android') shouldn't be needed. @benchmark.Enabled('android')
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py index f2260d5..eaed3f4 100644 --- a/tools/perf/benchmarks/rasterize_and_record_micro.py +++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -46,7 +46,9 @@ # RasterizeAndRecord disabled on mac because of crbug.com/350684. # RasterizeAndRecord disabled on windows because of crbug.com/338057. -@benchmark.Disabled('mac', 'win') +# RasterizeAndRecord disabled on linux because of crbug.com/600377. +# RasterizeAndRecord disabled on android because of crbug.com/605120. +@benchmark.Disabled('mac', 'win', 'linux', 'android') class RasterizeAndRecordMicroTop25(_RasterizeAndRecordMicro): """Measures rasterize and record performance on the top 25 web pages.
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index 4162a15..ae70a60 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -116,6 +116,7 @@ deps += [ "//ui/events:events_base", "//ui/events/devices", + "//ui/events/devices/x11", "//ui/events/platform/x11", "//ui/gfx/x", ]
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index 2e6ff1a..d39e82f 100644 --- a/ui/aura/aura.gyp +++ b/ui/aura/aura.gyp
@@ -118,6 +118,7 @@ '../../build/linux/system.gyp:xrandr', '../../build/linux/system.gyp:xi', '../events/devices/events_devices.gyp:events_devices', + '../events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', '../gfx/x/gfx_x11.gyp:gfx_x11', ],
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc index 2d679e5..10c45ca3 100644 --- a/ui/aura/test/aura_test_helper.cc +++ b/ui/aura/test/aura_test_helper.cc
@@ -67,9 +67,12 @@ ui::InitializeInputMethodForTesting(); - gfx::Size host_size(800, 600); + gfx::Screen* screen = gfx::Screen::GetScreen(); + gfx::Size host_size(screen ? screen->GetPrimaryDisplay().GetSizeInPixel() + : gfx::Size(800, 600)); test_screen_.reset(TestScreen::Create(host_size)); - gfx::Screen::SetScreenInstance(test_screen_.get()); + if (!screen) + gfx::Screen::SetScreenInstance(test_screen_.get()); host_.reset(test_screen_->CreateHostForPrimaryDisplay()); focus_client_.reset(new TestFocusClient);
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 6390bd4e..a4f296f 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -412,6 +412,8 @@ "dragdrop/drag_utils_aura.cc", ] } + + # TODO(kylechar): remove ozone_platform_x11 from here. if (use_x11 || ozone_platform_x11) { sources += [ "x/x11_foreign_window_manager.cc", @@ -431,7 +433,10 @@ ] configs += [ "//build/config/linux:xscrnsaver" ] } - deps += [ "//ui/gfx/x" ] + deps += [ + "//ui/events/devices/x11", + "//ui/gfx/x", + ] } if (!use_aura || !is_linux) {
diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp index c8c369d..06a52ffe 100644 --- a/ui/base/ui_base.gyp +++ b/ui/base/ui_base.gyp
@@ -607,6 +607,7 @@ '../../build/linux/system.gyp:xfixes', '../../build/linux/system.gyp:xrender', # For XRender* function calls in x11_util.cc. '../events/devices/events_devices.gyp:events_devices', + '../events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', '../gfx/x/gfx_x11.gyp:gfx_x11', ],
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index a7fc9af..0787103 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -165,6 +165,7 @@ ] deps += [ "//ui/events/devices", + "//ui/events/devices/x11", "//ui/gfx/x", ] } @@ -338,7 +339,7 @@ "test/events_test_utils_x11.h", ] deps += [ - "//ui/events/devices", + "//ui/events/devices/x11", "//ui/gfx/x", ] } @@ -425,6 +426,7 @@ ] configs += [ "//build/config/linux:x11" ] deps += [ + "//ui/events/devices/x11", "//ui/events/x", "//ui/gfx/x", ]
diff --git a/ui/events/devices/BUILD.gn b/ui/events/devices/BUILD.gn index f3dbfd5..c440545 100644 --- a/ui/events/devices/BUILD.gn +++ b/ui/events/devices/BUILD.gn
@@ -2,9 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/ui.gni") -import("//ui/ozone/ozone.gni") - component("devices") { sources = [ "device_data_manager.cc", @@ -31,22 +28,4 @@ "//ui/gfx", "//ui/gfx/geometry", ] - - if (use_x11 || ozone_platform_x11) { - configs += [ "//build/config/linux:x11" ] - - sources += [ - "x11/device_data_manager_x11.cc", - "x11/device_data_manager_x11.h", - "x11/device_list_cache_x11.cc", - "x11/device_list_cache_x11.h", - "x11/touch_factory_x11.cc", - "x11/touch_factory_x11.h", - ] - - deps += [ - "//ui/events:events_base", - "//ui/gfx/x", - ] - } }
diff --git a/ui/events/devices/events_devices.gyp b/ui/events/devices/events_devices.gyp index 1a20ee7..f0e1563 100644 --- a/ui/events/devices/events_devices.gyp +++ b/ui/events/devices/events_devices.gyp
@@ -34,25 +34,10 @@ 'keyboard_device.h', 'touchscreen_device.cc', 'touchscreen_device.h', - 'x11/device_data_manager_x11.cc', - 'x11/device_data_manager_x11.h', - 'x11/device_list_cache_x11.cc', - 'x11/device_list_cache_x11.h', - 'x11/touch_factory_x11.cc', - 'x11/touch_factory_x11.h', ], 'export_dependent_settings': [ '../../../ui/gfx/gfx.gyp:gfx', ], - 'conditions': [ - ['use_x11==1', { - 'dependencies': [ - '../../../build/linux/system.gyp:x11', - '../../../ui/events/events.gyp:events_base', - '../../../ui/gfx/x/gfx_x11.gyp:gfx_x11', - ], - }], - ], }, ], }
diff --git a/ui/events/devices/x11/BUILD.gn b/ui/events/devices/x11/BUILD.gn new file mode 100644 index 0000000..1aa7ed70 --- /dev/null +++ b/ui/events/devices/x11/BUILD.gn
@@ -0,0 +1,32 @@ +# Copyright 2016 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. + +component("x11") { + output_name = "events_devices_x11" + + sources = [ + "device_data_manager_x11.cc", + "device_data_manager_x11.h", + "device_list_cache_x11.cc", + "device_list_cache_x11.h", + "events_devices_x11_export.h", + "touch_factory_x11.cc", + "touch_factory_x11.h", + ] + + configs += [ "//build/config/linux:x11" ] + + defines = [ "EVENTS_DEVICES_X11_IMPLEMENTATION" ] + + deps = [ + "//base", + "//base/third_party/dynamic_annotations", + "//skia", + "//ui/events:events_base", + "//ui/events/devices", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gfx/x", + ] +}
diff --git a/ui/events/devices/x11/device_data_manager_x11.h b/ui/events/devices/x11/device_data_manager_x11.h index d09cf34..072378e 100644 --- a/ui/events/devices/x11/device_data_manager_x11.h +++ b/ui/events/devices/x11/device_data_manager_x11.h
@@ -24,7 +24,7 @@ #include "base/event_types.h" #include "base/macros.h" #include "ui/events/devices/device_data_manager.h" -#include "ui/events/devices/events_devices_export.h" +#include "ui/events/devices/x11/events_devices_x11_export.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/rect.h" @@ -49,7 +49,8 @@ // A class that extracts and tracks the input events data. It currently handles // mouse, touchpad and touchscreen devices. -class EVENTS_DEVICES_EXPORT DeviceDataManagerX11 : public DeviceDataManager { +class EVENTS_DEVICES_X11_EXPORT DeviceDataManagerX11 + : public DeviceDataManager { public: // Enumerate additional data that one might be interested on an input event, // which are usually wrapped in X valuators. If you modify any of this,
diff --git a/ui/events/devices/x11/device_list_cache_x11.h b/ui/events/devices/x11/device_list_cache_x11.h index 2ff3943a..1618fc14 100644 --- a/ui/events/devices/x11/device_list_cache_x11.h +++ b/ui/events/devices/x11/device_list_cache_x11.h
@@ -12,7 +12,7 @@ #include <memory> #include "base/macros.h" -#include "ui/events/devices/events_devices_export.h" +#include "ui/events/devices/x11/events_devices_x11_export.h" #include "ui/gfx/x/x11_types.h" namespace base { @@ -38,7 +38,7 @@ // A class to cache the current XInput device list. This minimized the // round-trip time to the X server whenever such a device list is needed. The // update function will be called on each incoming XI_HierarchyChanged event. -class EVENTS_DEVICES_EXPORT DeviceListCacheX11 { +class EVENTS_DEVICES_X11_EXPORT DeviceListCacheX11 { public: static DeviceListCacheX11* GetInstance();
diff --git a/ui/events/devices/x11/events_devices_x11.gyp b/ui/events/devices/x11/events_devices_x11.gyp new file mode 100644 index 0000000..1093f99c --- /dev/null +++ b/ui/events/devices/x11/events_devices_x11.gyp
@@ -0,0 +1,38 @@ +# Copyright 2016 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'events_devices_x11', + 'type': '<(component)', + 'dependencies': [ + '../../../../base/base.gyp:base', + '../../../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '../../../../build/linux/system.gyp:x11', + '../../../../skia/skia.gyp:skia', + '../../../../ui/events/events.gyp:events_base', + '../../../../ui/events/devices/events_devices.gyp:events_devices', + '../../../../ui/gfx/gfx.gyp:gfx', + '../../../../ui/gfx/gfx.gyp:gfx_geometry', + '../../../../ui/gfx/x/gfx_x11.gyp:gfx_x11', + ], + 'defines': [ + 'EVENTS_DEVICES_X11_IMPLEMENTATION', + ], + 'sources': [ + 'device_data_manager_x11.cc', + 'device_data_manager_x11.h', + 'device_list_cache_x11.cc', + 'device_list_cache_x11.h', + 'events_devices_x11_export.h', + 'touch_factory_x11.cc', + 'touch_factory_x11.h', + ], + }, + ], +}
diff --git a/ui/events/devices/x11/events_devices_x11_export.h b/ui/events/devices/x11/events_devices_x11_export.h new file mode 100644 index 0000000..cf5f77df --- /dev/null +++ b/ui/events/devices/x11/events_devices_x11_export.h
@@ -0,0 +1,29 @@ +// Copyright 2016 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 UI_EVENTS_DEVICES_X11_EVENTS_DEVICES_X11_EXPORT_H_ +#define UI_EVENTS_DEVICES_X11_EVENTS_DEVICES_X11_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(EVENTS_DEVICES_X11_IMPLEMENTATION) +#define EVENTS_DEVICES_X11_EXPORT __declspec(dllexport) +#else +#define EVENTS_DEVICES_X11_EXPORT __declspec(dllimport) +#endif // defined(EVENTS_DEVICES_X11_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(EVENTS_DEVICES_X11_IMPLEMENTATION) +#define EVENTS_DEVICES_X11_EXPORT __attribute__((visibility("default"))) +#else +#define EVENTS_DEVICES_X11_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define EVENTS_DEVICES_X11_EXPORT +#endif + +#endif // UI_EVENTS_DEVICES_X11_EVENTS_DEVICES_X11_EXPORT_H_
diff --git a/ui/events/devices/x11/touch_factory_x11.h b/ui/events/devices/x11/touch_factory_x11.h index 496dcb5..7588398 100644 --- a/ui/events/devices/x11/touch_factory_x11.h +++ b/ui/events/devices/x11/touch_factory_x11.h
@@ -14,7 +14,7 @@ #include <vector> #include "base/macros.h" -#include "ui/events/devices/events_devices_export.h" +#include "ui/events/devices/x11/events_devices_x11_export.h" #include "ui/gfx/sequential_id_generator.h" namespace base { @@ -30,7 +30,7 @@ namespace ui { // Functions related to determining touch devices. -class EVENTS_DEVICES_EXPORT TouchFactory { +class EVENTS_DEVICES_X11_EXPORT TouchFactory { private: TouchFactory(); ~TouchFactory();
diff --git a/ui/events/events.gyp b/ui/events/events.gyp index c8d994f..cf1ed63 100644 --- a/ui/events/events.gyp +++ b/ui/events/events.gyp
@@ -162,6 +162,7 @@ '../../build/linux/system.gyp:x11', '../gfx/x/gfx_x11.gyp:gfx_x11', 'devices/events_devices.gyp:events_devices', + 'devices/x11/events_devices_x11.gyp:events_devices_x11', 'x/events_x.gyp:events_x', ], }], @@ -362,6 +363,11 @@ # The cocoa files don't apply to iOS. 'sources/': [['exclude', 'cocoa']], }], + ['use_x11==1', { + 'dependencies': [ + 'devices/x11/events_devices_x11.gyp:events_devices_x11', + ], + }], ['use_x11==1 or use_ozone==1', { 'sources' : [ 'test/device_data_manager_test_api_impl.cc',
diff --git a/ui/events/events_unittests.gyp b/ui/events/events_unittests.gyp index f5a5d01c..f8e0ed9 100644 --- a/ui/events/events_unittests.gyp +++ b/ui/events/events_unittests.gyp
@@ -72,7 +72,8 @@ 'dependencies': [ '../../build/linux/system.gyp:x11', '../gfx/x/gfx_x11.gyp:gfx_x11', - 'x/events_x.gyp:events_x', + 'devices/x11/events_devices_x11.gyp:events_devices_x11', + 'x/events_x.gyp:events_x', ], }], ['use_ozone==1', {
diff --git a/ui/events/platform/x11/BUILD.gn b/ui/events/platform/x11/BUILD.gn index 929613c7f..a4801af 100644 --- a/ui/events/platform/x11/BUILD.gn +++ b/ui/events/platform/x11/BUILD.gn
@@ -25,6 +25,7 @@ "//ui/events", "//ui/events:events_base", "//ui/events/devices", + "//ui/events/devices/x11", "//ui/events/platform", "//ui/events/x", "//ui/gfx/x",
diff --git a/ui/events/platform/x11/x11_events_platform.gyp b/ui/events/platform/x11/x11_events_platform.gyp index a624722..de6a9b9 100644 --- a/ui/events/platform/x11/x11_events_platform.gyp +++ b/ui/events/platform/x11/x11_events_platform.gyp
@@ -18,6 +18,7 @@ '../../../../build/linux/system.gyp:x11', '../../../gfx/x/gfx_x11.gyp:gfx_x11', '../../devices/events_devices.gyp:events_devices', + '../../devices/x11/events_devices_x11.gyp:events_devices_x11', '../../events.gyp:events', '../../events.gyp:events_base', '../../x/events_x.gyp:events_x',
diff --git a/ui/events/x/BUILD.gn b/ui/events/x/BUILD.gn index 991ce6e..bff8a29 100644 --- a/ui/events/x/BUILD.gn +++ b/ui/events/x/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. component("x") { + output_name = "events_x" sources = [ "events_x_export.h", "events_x_utils.cc", @@ -14,6 +15,7 @@ "//skia", "//ui/events:events_base", "//ui/events/devices", + "//ui/events/devices/x11", "//ui/gfx/x", ] configs += [ "//build/config/linux:x11" ]
diff --git a/ui/events/x/events_x.gyp b/ui/events/x/events_x.gyp index 0432178..9b3f802 100644 --- a/ui/events/x/events_x.gyp +++ b/ui/events/x/events_x.gyp
@@ -15,6 +15,7 @@ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/skia/skia.gyp:skia', '../../events/devices/events_devices.gyp:events_devices', + '../../events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../../events/events.gyp:events_base', '../../gfx/x/gfx_x11.gyp:gfx_x11', ],
diff --git a/ui/login/account_picker/screen_account_picker.js b/ui/login/account_picker/screen_account_picker.js index fa287e2a..cccf723 100644 --- a/ui/login/account_picker/screen_account_picker.js +++ b/ui/login/account_picker/screen_account_picker.js
@@ -203,6 +203,9 @@ loadUsers: function(users, showGuest) { $('pod-row').loadPods(users); $('login-header-bar').showGuestButton = showGuest; + // On Desktop, #login-header-bar has a shadow if there are 8+ profiles. + if (Oobe.getInstance().displayType == DISPLAY_TYPE.DESKTOP_USER_MANAGER) + $('login-header-bar').classList.toggle('shadow', users.length > 8); }, /**
diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css index 88f117b..32a1f93c 100644 --- a/ui/login/account_picker/user_pod_row.css +++ b/ui/login/account_picker/user_pod_row.css
@@ -433,6 +433,16 @@ background-image: url(chrome://theme/IDR_OOBE_ACTION_BOX_BUTTON_PRESSED); } +.action-box-area .action-box-icon { + /* overriden in chrome/browser/resources/md_user_manager/user_manager.css */ + display: none; +} + +.user-image-gradient-area { + /* overriden in chrome/browser/resources/md_user_manager/user_manager.css */ + display: none; +} + .user-type-icon-area { left: 0; z-index: 5; @@ -571,9 +581,18 @@ } .action-box-remove-user-warning .remove-warning-button { + background: rgb(197, 57, 41); + border-radius: 2px; + color: white; + line-height: 32px; + padding: 0 16px; width: 100%; } +.action-box-remove-user-warning .remove-warning-button.keyboard-focus { + font-weight: normal; +} + /* Hide dialog elements not in a correct category. Only combinations currently in use are included here. */ .pod.legacy-supervised .non-sync,
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index 8bc93b9..5beacb4 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js
@@ -28,7 +28,7 @@ * @type {Array<number>} * @const */ - var DESKTOP_MARGIN_BY_COLUMNS = [undefined, 15, 15, 15, 15, 15, 15]; + var DESKTOP_MARGIN_BY_COLUMNS = [undefined, 32, 32, 32, 32, 32, 32]; /** * Maximal number of columns currently supported by pod-row. @@ -48,13 +48,16 @@ * Variables used for pod placement processing. Width and height should be * synced with computed CSS sizes of pods. */ - var POD_WIDTH = 180; + var CROS_POD_WIDTH = 180; + var DESKTOP_POD_WIDTH = 180; + var MD_DESKTOP_POD_WIDTH = 160; var PUBLIC_EXPANDED_BASIC_WIDTH = 500; var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610; var CROS_POD_HEIGHT = 213; var DESKTOP_POD_HEIGHT = 226; + var MD_DESKTOP_POD_HEIGHT = 200; var POD_ROW_PADDING = 10; - var DESKTOP_ROW_PADDING = 15; + var DESKTOP_ROW_PADDING = 32; var CUSTOM_ICON_CONTAINER_SIZE = 40; /** @@ -1548,19 +1551,26 @@ if (profilePath !== this.user.profilePath) return; // Add localized messages where $1 will be replaced with - // <span class="total-count"></span>. + // <span class="total-count"></span> and $2 will be replaced with + // <span class="email"></span>. var element = this.querySelector('.action-box-remove-user-warning-text'); element.textContent = ''; - messageParts = message.split('$1'); + messageParts = message.split(/(\$[12])/); var numParts = messageParts.length; for (var j = 0; j < numParts; j++) { - element.appendChild(document.createTextNode(messageParts[j])); - if (j < numParts - 1) { + if (messageParts[j] === '$1') { var elementToAdd = document.createElement('span'); elementToAdd.classList.add('total-count'); elementToAdd.textContent = count; element.appendChild(elementToAdd); + } else if (messageParts[j] === '$2') { + var elementToAdd = document.createElement('span'); + elementToAdd.classList.add('email'); + elementToAdd.textContent = this.user.emailAddress; + element.appendChild(elementToAdd); + } else { + element.appendChild(document.createTextNode(messageParts[j])); } } this.moveActionMenuUpIfNeeded_(); @@ -2312,10 +2322,15 @@ var isDesktopUserManager = Oobe.getInstance().displayType == DISPLAY_TYPE.DESKTOP_USER_MANAGER; - this.userPodHeight_ = isDesktopUserManager ? DESKTOP_POD_HEIGHT : - CROS_POD_HEIGHT; - // Same for Chrome OS and desktop. - this.userPodWidth_ = POD_WIDTH; + var isNewDesktopUserManager = Oobe.getInstance().newDesktopUserManager; + this.userPodHeight_ = isDesktopUserManager ? + isNewDesktopUserManager ? MD_DESKTOP_POD_HEIGHT : + DESKTOP_POD_HEIGHT : + CROS_POD_HEIGHT; + this.userPodWidth_ = isDesktopUserManager ? + isNewDesktopUserManager ? MD_DESKTOP_POD_WIDTH : + DESKTOP_POD_WIDTH : + CROS_POD_WIDTH; }, /** @@ -2793,9 +2808,11 @@ $('signin-banner'), null).getPropertyValue('display') != 'none') { rows = Math.min(rows, MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER); } - var maxHeigth = Oobe.getInstance().clientAreaSize.height; - while (maxHeigth < this.rowsToHeight_(rows) && rows > 1) - --rows; + if (!Oobe.getInstance().newDesktopUserManager) { + var maxHeigth = Oobe.getInstance().clientAreaSize.height; + while (maxHeigth < this.rowsToHeight_(rows) && rows > 1) + --rows; + } // One more iteration if it's not enough cells to place all pods. while (maxWidth >= this.columnsToWidth_(columns + 1) && columns * rows < this.pods.length &&
diff --git a/ui/login/account_picker/user_pod_template.html b/ui/login/account_picker/user_pod_template.html index cf302ba4..008b28c8 100644 --- a/ui/login/account_picker/user_pod_template.html +++ b/ui/login/account_picker/user_pod_template.html
@@ -52,6 +52,9 @@ </div> <div class="action-box-area"> <div class="custom-appearance action-box-button"></div> + <iron-icon icon="more-vert" class="action-box-icon"></iron-icon> + </div> + <div class="user-image-gradient-area"> </div> <div class="user-type-icon-area" hidden> <div class="custom-appearance user-type-icon-image"></div> @@ -97,9 +100,8 @@ </table> <div class="action-box-remove-legacy-supervised-user-warning-text" i18n-content="removeLegacySupervisedUserWarningText"></div> - <button class="remove-warning-button - custom-appearance button-fancy button-red" - i18n-content="removeUserWarningButtonTitle"></button> + <paper-button class="remove-warning-button" + i18n-content="removeUserWarningButtonTitle"></paper-button> </div> </div> <div class="user-type-bubble">
diff --git a/ui/login/account_picker/user_pod_template.js b/ui/login/account_picker/user_pod_template.js index 0a5ee8a..7853c5e 100644 --- a/ui/login/account_picker/user_pod_template.js +++ b/ui/login/account_picker/user_pod_template.js
@@ -16,6 +16,8 @@ } lazyLoadUrl('chrome://resources/polymer/v1_0/iron-icons/iron-icons.html'); + lazyLoadUrl( + 'chrome://resources/polymer/v1_0/paper-button/paper-button.html'); } window.addEventListener('load', function() {
diff --git a/ui/platform_window/x11/BUILD.gn b/ui/platform_window/x11/BUILD.gn index bac1aaa..d3edc9a 100644 --- a/ui/platform_window/x11/BUILD.gn +++ b/ui/platform_window/x11/BUILD.gn
@@ -15,6 +15,7 @@ "//skia", "//ui/events", "//ui/events/devices", + "//ui/events/devices/x11", "//ui/events/platform", "//ui/events/platform/x11", "//ui/gfx/x",
diff --git a/ui/platform_window/x11/x11_window.gyp b/ui/platform_window/x11/x11_window.gyp index f4b948a..b81fbd2 100644 --- a/ui/platform_window/x11/x11_window.gyp +++ b/ui/platform_window/x11/x11_window.gyp
@@ -17,6 +17,7 @@ '../../../skia/skia.gyp:skia', '../../events/devices/events_devices.gyp:events_devices', '../../events/events.gyp:events', + '../../events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../../events/platform/events_platform.gyp:events_platform', '../../events/platform/x11/x11_events_platform.gyp:x11_events_platform', '../../gfx/x/gfx_x11.gyp:gfx_x11',
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 576c2b72..b7b01f37 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -105,6 +105,7 @@ ] deps += [ "//ui/events/devices", + "//ui/events/devices/x11", "//ui/events/platform/x11", "//ui/gfx/x", ]
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn index 3e058c6..b166f85 100644 --- a/ui/views/mus/BUILD.gn +++ b/ui/views/mus/BUILD.gn
@@ -152,6 +152,7 @@ "native_widget_mus_unittest.cc", "platform_test_helper_mus.cc", "run_all_unittests_mus.cc", + "screen_mus_unittest.cc", ] deps = [
diff --git a/ui/views/mus/screen_mus.cc b/ui/views/mus/screen_mus.cc index d22499c..faa31ad 100644 --- a/ui/views/mus/screen_mus.cc +++ b/ui/views/mus/screen_mus.cc
@@ -17,9 +17,19 @@ template <> struct TypeConverter<gfx::Display, mus::mojom::DisplayPtr> { static gfx::Display Convert(const mus::mojom::DisplayPtr& input) { - gfx::Display result(input->id, input->bounds.To<gfx::Rect>()); - result.set_work_area(input->work_area.To<gfx::Rect>()); + gfx::Display result(input->id); + gfx::Rect pixel_bounds = input->bounds.To<gfx::Rect>(); + gfx::Rect pixel_work_area = input->work_area.To<gfx::Rect>(); + float pixel_ratio = input->device_pixel_ratio; + + gfx::Rect dip_bounds = + gfx::ScaleToEnclosingRect(pixel_bounds, 1.f / pixel_ratio); + gfx::Rect dip_work_area = + gfx::ScaleToEnclosingRect(pixel_work_area, 1.f / pixel_ratio); + result.set_bounds(dip_bounds); + result.set_work_area(dip_work_area); result.set_device_scale_factor(input->device_pixel_ratio); + switch (input->rotation) { case mus::mojom::Rotation::VALUE_0: result.set_rotation(gfx::Display::ROTATE_0);
diff --git a/ui/views/mus/screen_mus_unittest.cc b/ui/views/mus/screen_mus_unittest.cc new file mode 100644 index 0000000..fe80a72b --- /dev/null +++ b/ui/views/mus/screen_mus_unittest.cc
@@ -0,0 +1,32 @@ +// Copyright 2016 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 "ui/views/mus/screen_mus.h" + +#include "base/command_line.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/switches.h" +#include "ui/views/mus/window_manager_connection.h" +#include "ui/views/test/scoped_views_test_helper.h" +#include "ui/views/test/views_test_base.h" + +namespace views { +namespace { + +TEST(ScreenMusTest, ConsistentDisplayInHighDPI) { + base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kForceDeviceScaleFactor, "2"); + ScopedViewsTestHelper test_helper; + gfx::Screen* screen = gfx::Screen::GetScreen(); + std::vector<gfx::Display> displays = screen->GetAllDisplays(); + ASSERT_FALSE(displays.empty()); + for (const gfx::Display& display : displays) { + EXPECT_EQ(2.f, display.device_scale_factor()); + EXPECT_EQ(display.work_area(), display.bounds()); + } +} + +} // namespace +} // namespace views
diff --git a/ui/views/views.gyp b/ui/views/views.gyp index dc89d3c..92476a2 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp
@@ -763,6 +763,7 @@ '../../build/linux/system.gyp:x11', '../../build/linux/system.gyp:xrandr', '../events/devices/events_devices.gyp:events_devices', + '../events/devices/x11/events_devices_x11.gyp:events_devices_x11', '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', '../gfx/x/gfx_x11.gyp:gfx_x11', ],
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn index 3be6e2d8..1881478 100644 --- a/ui/wm/BUILD.gn +++ b/ui/wm/BUILD.gn
@@ -85,6 +85,7 @@ if (use_x11) { configs += [ "//build/config/linux:x11" ] + deps += [ "//ui/events/devices/x11" ] } }
diff --git a/ui/wm/core/compound_event_filter.cc b/ui/wm/core/compound_event_filter.cc index 70f76c6..74ecae27 100644 --- a/ui/wm/core/compound_event_filter.cc +++ b/ui/wm/core/compound_event_filter.cc
@@ -18,7 +18,7 @@ #include "ui/wm/public/drag_drop_client.h" #if defined(OS_CHROMEOS) && defined(USE_X11) -#include "ui/events/devices/x11/touch_factory_x11.h" +#include "ui/events/devices/x11/touch_factory_x11.h" // nogncheck #endif namespace wm {
diff --git a/ui/wm/wm.gyp b/ui/wm/wm.gyp index 685c9769..aa7ef5ac 100644 --- a/ui/wm/wm.gyp +++ b/ui/wm/wm.gyp
@@ -91,6 +91,7 @@ ['use_x11==1', { 'dependencies': [ '../../build/linux/system.gyp:x11', + '../events/devices/x11/events_devices_x11.gyp:events_devices_x11', ], }], ],