Automated commit: libchrome r1307197 uprev
Merge with upstream commit 1347cb89b87ea43de8127c82d346747b54b3bb59
BUG=None
TEST=sudo emerge libchrome
Change-Id: I22933113de227122f73bd0a74ed9f57685cfe1a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/libchrome/+/5577401
Bot-Commit: ChromeOS Prod (Robot) <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>
Commit-Queue: ChromeOS Prod (Robot) <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>
Tested-by: ChromeOS Prod (Robot) <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/BASE_VER b/BASE_VER
new file mode 100644
index 0000000..4afb858
--- /dev/null
+++ b/BASE_VER
@@ -0,0 +1 @@
+1307197
diff --git a/BUILD.IGNORE b/BUILD.IGNORE
new file mode 100644
index 0000000..d84edf6
--- /dev/null
+++ b/BUILD.IGNORE
@@ -0,0 +1,10 @@
+android
+components/policy
+fuzzer
+perftest
+power_monitor
+test_runner
+tests
+trace_event
+ui/gfx
+unittest
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..20d12e3
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,1532 @@
+# Copyright 2018 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# BUILD.gn doesn't compile all files in the directory to reduce build size.
+# Missing files can be added if needed.
+
+import("//common-mk/mojom_bindings_generator.gni")
+import("//common-mk/mojom_type_mappings_generator.gni")
+import("//common-mk/pkg_config.gni")
+import("//common-mk/proto_library.gni")
+import("//libchrome/base/allocator/partition_allocator/src/partition_alloc/buildflag_header.gni")
+import("//libchrome/build/buildflag_header.gni")
+
+libchrome_basever = read_file("BASE_VER", "trim string")
+
+# Enable //base/allocator shim for non-sanitizer builds.
+use_allocator_shim = !(use.asan || use.fuzzer || use.msan || use.ubsan)
+
+group("all") {
+ deps = [
+ ":install_basever",
+ ":install_buildflag_header",
+ ":install_header",
+ ":install_protozero_generated",
+ ":libchrome",
+ ":libchrome-test",
+ ]
+ if (use.mojo) {
+ deps += [
+ ":install_mojom_generated",
+ ":libmojo",
+ ]
+ }
+ if (use.test) {
+ deps += [ ":optional_unittests" ]
+ }
+}
+
+group("all_buildflags") {
+ deps = [
+ ":allocator_buildflags",
+ ":allocator_debugging_buildflags",
+ ":allocator_logging_buildflags",
+ ":blink_buildflags",
+ ":branding_buildflags",
+ ":cfi_buildflags",
+ ":chromecast_buildflags",
+ ":chromeos_buildflags",
+ ":clang_profiling_buildflags",
+ ":compiler_buildflags",
+ ":debugging_buildflags",
+ ":feature_list_buildflags",
+ ":fuzzing_buildflags",
+ ":ios_buildflags",
+ ":ios_cronet_buildflags",
+ ":ipc_buildflags",
+ ":message_pump_buildflags",
+ ":mojo_buildflags",
+ ":mojo_cpp_bindings_buildflags",
+ ":partition_allocator_buildflags",
+ ":partition_allocator_chromecast_buildflags",
+ ":partition_allocator_chromeos_buildflags",
+ ":partition_allocator_raw_ptr_buildflags",
+ ":profiler_buildflags",
+ ":rust_buildflags",
+ ":synchronization_buildflags",
+ ":tracing_buildflags",
+ ":protected_memory_buildflags",
+ ]
+}
+
+config("libchrome_config") {
+ # TODO(hidehiko): Consolidate with build_config.h.
+ defines = [
+ "OS_CHROMEOS",
+ "USE_NSS_CERTS",
+ "USE_SYSTEM_LIBEVENT",
+ "NO_TCMALLOC",
+ "MOJO_BACKWARDS_COMPAT",
+ "MOJO_CORE_LEGACY_PROTOCOL",
+ "BASE_USE_PERFETTO_CLIENT_LIBRARY",
+ "PERFETTO_ENABLE_LEGACY_TRACE_EVENTS",
+ ]
+ if (use.asan) {
+ defines += [
+ "LEAK_SANITIZER",
+ "DISABLE_ALLOCATOR_SANITIZER",
+ ]
+ }
+
+ include_dirs = [
+ ".",
+ "${root_gen_dir}/libchrome", # for generated buildflags headers
+ "third_party/perfetto/include", # for generated protozero headers
+ ]
+ cflags = [
+ "-Wno-deprecated-register",
+ "-Wno-narrowing",
+ "-Wno-unreachable-code-return",
+ "-Wno-unused-local-typedefs",
+ # TODO(b/314188050): Reenable Wvla-extension after Chrome cleans it up.
+ "-Wno-error=vla-cxx-extension",
+ "-Xclang-only=-Wno-char-subscripts",
+ ]
+
+ # Prevent --gc-sections from removing unused perfetto symbols, because
+ # clients of libchrome (e.g., libbrillo) may need them. This avoids having to
+ # statically link separate copies of perfetto into each library.
+ ldflags = [ "-Wl,--undefined-glob=*perfetto*SystemProducer*" ]
+
+ # Address sanitizer + coverage builds do not support -z,defs.
+ if (!(use.asan || use.coverage)) {
+ ldflags += [ "-Wl,-z,defs" ]
+ }
+}
+
+config("base_core_config") {
+ cflags = [
+ # Suppressing warning in base/strings/stringprintf.cc.
+ "-Wno-format-nonliteral",
+
+ # This is for _exit(1) in base/debug/debugger_posix.cc.
+ "-Wno-unreachable-code",
+
+ # For double-conversion/strtod.cc
+ "-Wno-unused-function",
+ ]
+}
+
+config("base_export_config") {
+ defines = [
+ "COMPONENT_BUILD",
+ "BASE_IMPLEMENTATION",
+ "IS_PARTITION_ALLOC_IMPL",
+ ]
+}
+
+config("crypto_export_config") {
+ defines = [
+ "COMPONENT_BUILD",
+ "CRYPTO_IMPLEMENTATION",
+ ]
+}
+
+config("dbus_export_config") {
+ defines = [
+ "COMPONENT_BUILD",
+ "DBUS_IMPLEMENTATION",
+ ]
+}
+
+config("policy_export_config") {
+ defines = [
+ "COMPONENT_BUILD",
+ "POLICY_COMPONENT_IMPLEMENTATION",
+ ]
+}
+
+config("mojo_export_config") {
+ defines = [ "COMPONENT_BUILD" ]
+}
+
+source_set("buildflag_header_h") {
+ sources = [ "build/buildflag.h" ]
+}
+
+buildflag_header("allocator_buildflags") {
+ header = "base/allocator/buildflags.h"
+ flags = [
+ "USE_ALLOCATOR_SHIM=$use_allocator_shim",
+ "USE_PARTITION_ALLOC=false",
+ "USE_PARTITION_ALLOC_AS_MALLOC=false",
+ "USE_BACKUP_REF_PTR=false",
+ "USE_ASAN_BACKUP_REF_PTR=false",
+ "USE_MTE_CHECKED_PTR=false",
+ ]
+}
+
+buildflag_header("allocator_logging_buildflags") {
+ header = "base/allocator/partition_allocator/src/partition_alloc/logging_buildflags.h"
+
+ flags = [ "PA_ENABLE_LOG_ERROR_NOT_REACHED=false" ]
+}
+
+pa_buildflag_header("partition_allocator_buildflags") {
+ # Copied from base/allocator/partition_allocator/src/partition_alloc/partition_alloc.gni without
+ # using is_nacl.
+ if (current_cpu == "x64" || current_cpu == "arm64") {
+ has_64_bit_pointers = true
+ } else if (current_cpu == "x86" || current_cpu == "arm") {
+ has_64_bit_pointers = false
+ } else {
+ assert(false, "Unknown CPU: $current_cpu")
+ }
+
+ header = "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_buildflags.h"
+ flags = [
+ "HAS_64_BIT_POINTERS=$has_64_bit_pointers",
+ "USE_PARTITION_ALLOC=false",
+ "USE_PARTITION_ALLOC_AS_MALLOC=false",
+ "USE_ASAN_BACKUP_REF_PTR=false",
+ "USE_HOOKABLE_RAW_PTR=false",
+ "USE_RAW_PTR_ASAN_UNOWNED_IMPL=false",
+ "USE_RAW_PTR_BACKUP_REF_IMPL=false",
+ "USE_RAW_PTR_HOOKABLE_IMPL=false",
+ "USE_ALLOCATOR_SHIM=$use_allocator_shim",
+ "BACKUP_REF_PTR_POISON_OOB_PTR=false",
+ "ENABLE_PARTITION_ALLOC_AS_MALLOC_SUPPORT=false",
+ "ENABLE_BACKUP_REF_PTR_SUPPORT=false",
+ "ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=false",
+ "ENABLE_DANGLING_RAW_PTR_CHECKS=false",
+ "PUT_REF_COUNT_IN_PREVIOUS_SLOT=false",
+ "ENABLE_MTE_CHECKED_PTR_SUPPORT=false",
+ "RECORD_ALLOC_INFO=false",
+ "GLUE_CORE_POOLS=false",
+ "ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=false",
+ "USE_STARSCAN=false",
+ "PA_USE_BASE_TRACING=false",
+ "ENABLE_PKEYS=false",
+ "ENABLE_POINTER_COMPRESSION=false",
+ "USE_ASAN_UNOWNED_PTR=false",
+ "FORCE_ENABLE_RAW_PTR_EXCLUSION=false",
+ "ENABLE_RAW_PTR_EXPERIMENTAL=false",
+ "ENABLE_THREAD_ISOLATION=false",
+ "USE_FREESLOT_BITMAP=false",
+ "ENABLE_POINTER_ARITHMETIC_TRAIT_CHECK=false",
+ "HAS_MEMORY_TAGGING=false",
+ "FORWARD_THROUGH_MALLOC=false",
+ "ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER=false",
+ "ASSERT_CPP_20=true",
+ "USE_LARGE_EMPTY_SLOT_SPAN_RING=false",
+ ]
+}
+
+pa_buildflag_header("partition_allocator_raw_ptr_buildflags") {
+ header = "base/allocator/partition_allocator/src/partition_alloc/raw_ptr_buildflags.h"
+
+ flags = [
+ "RAW_PTR_ZERO_ON_CONSTRUCT=true",
+ "RAW_PTR_ZERO_ON_MOVE=true",
+ "RAW_PTR_ZERO_ON_DESTRUCT=false",
+ ]
+}
+
+pa_buildflag_header("partition_allocator_chromecast_buildflags") {
+ header = "base/allocator/partition_allocator/src/partition_alloc/chromecast_buildflags.h"
+ flags = [
+ "PA_IS_CAST_ANDROID=false",
+ "PA_IS_CASTOS=false",
+ ]
+}
+
+pa_buildflag_header("partition_allocator_chromeos_buildflags") {
+ header = "base/allocator/partition_allocator/src/partition_alloc/chromeos_buildflags.h"
+ flags = [ "PA_IS_CHROMEOS_ASH=false" ]
+}
+
+pa_buildflag_header("allocator_debugging_buildflags") {
+ header = "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/debug/debugging_buildflags.h"
+ flags = [
+ "PA_DCHECK_IS_ON=false",
+ "PA_EXPENSIVE_DCHECKS_ARE_ON=false",
+ "PA_DCHECK_IS_CONFIGURABLE=false",
+ "PA_CAN_UNWIND_WITH_FRAME_POINTERS=false",
+ ]
+}
+
+buildflag_header("blink_buildflags") {
+ header = "build/blink_buildflags.h"
+
+ flags = [ "USE_BLINK=false" ]
+}
+
+buildflag_header("branding_buildflags") {
+ header = "build/branding_buildflags.h"
+
+ flags = [
+ "CHROMIUM_BRANDING=true",
+ "GOOGLE_CHROME_BRANDING=false",
+ ]
+}
+
+buildflag_header("cfi_buildflags") {
+ header = "base/cfi_buildflags.h"
+ flags = [
+ "CFI_DIAG=false",
+ "CFI_ICALL_CHECK=false",
+ "CFI_ENFORCEMENT_TRAP=false",
+ ]
+}
+
+buildflag_header("chromecast_buildflags") {
+ header = "build/chromecast_buildflags.h"
+ flags = [ "IS_CHROME_CAST=false" ]
+}
+
+buildflag_header("chromeos_buildflags") {
+ header = "build/chromeos_buildflags.h"
+ flags = [
+ "IS_CHROMEOS_DEVICE=false",
+ "IS_CHROMEOS_LACROS=false",
+ "IS_CHROMEOS_ASH=true",
+
+ # "IS_CHROMEOS_WITH_HW_DETAILS=",
+ # "IS_REVEN=",
+ ]
+}
+
+buildflag_header("clang_profiling_buildflags") {
+ header = "base/clang_profiling_buildflags.h"
+ flags = [
+ "CLANG_PROFILING=false",
+ # "CLANG_PROFILING_INSIDE_SANDBOX=",
+ # "USE_CLANG_COVERAGE=",
+ ]
+}
+
+buildflag_header("compiler_buildflags") {
+ header = "build/config/compiler/compiler_buildflags.h"
+ flags = [
+ "CLANG_PGO=0",
+ "SYMBOL_LEVEL=1",
+ ]
+}
+
+buildflag_header("debugging_buildflags") {
+ header = "base/debug/debugging_buildflags.h"
+ flags = [
+ "DCHECK_IS_CONFIGURABLE=false",
+ "ENABLE_LOCATION_SOURCE=true",
+ "FROM_HERE_USES_LOCATION_BUILTINS=true",
+ "ENABLE_PROFILING=false",
+ "CAN_UNWIND_WITH_FRAME_POINTERS=true",
+ "ENABLE_COMMANDLINE_SEQUENCE_CHECKS=true",
+
+ # "UNSAFE_DEVELOPER_BUILD=",
+ "CAN_UNWIND_WITH_CFI_TABLE=false",
+
+ # "EXCLUDE_UNWIND_TABLES=",
+ "ENABLE_GDBINIT_WARNING=false",
+
+ # "ENABLE_LLDBINIT_WARNING=",
+ "EXPENSIVE_DCHECKS_ARE_ON=false",
+
+ # "ENABLE_STACK_TRACE_LINE_NUMBERS=",
+ ]
+}
+
+buildflag_header("feature_list_buildflags") {
+ header = "base/feature_list_buildflags.h"
+ flags = [ "ENABLE_BANNED_BASE_FEATURE_PREFIX=false" ]
+}
+
+buildflag_header("fuzzing_buildflags") {
+ header = "base/fuzzing_buildflags.h"
+ flags = [ "USE_FUZZING_ENGINE=false" ]
+}
+
+buildflag_header("ios_buildflags") {
+ header = "build/ios_buildflags.h"
+ flags = [ "IS_IOS_APP_EXTENSION=false" ]
+}
+
+buildflag_header("ios_cronet_buildflags") {
+ header = "base/message_loop/ios_cronet_buildflags.h"
+ flags = [ "CRONET_BUILD=false" ]
+}
+
+buildflag_header("ipc_buildflags") {
+ header = "ipc/ipc_buildflags.h"
+ flags = [ "IPC_MESSAGE_LOG_ENABLED=false" ]
+}
+
+buildflag_header("message_pump_buildflags") {
+ header = "base/message_loop/message_pump_buildflags.h"
+ flags = [ "ENABLE_MESSAGE_PUMP_EPOLL=true" ]
+}
+
+buildflag_header("mojo_buildflags") {
+ header = "mojo/buildflags.h"
+ flags = [ "MOJO_USE_APPLE_CHANNEL=false" ]
+}
+
+buildflag_header("mojo_cpp_bindings_buildflags") {
+ header = "mojo/public/cpp/bindings/mojo_buildflags.h"
+ flags = [
+ "MOJO_TRACE_ENABLED=false",
+ "MOJO_RANDOM_DELAYS_ENABLED=false",
+ ]
+}
+
+buildflag_header("profiler_buildflags") {
+ header = "base/profiler/profiler_buildflags.h"
+ flags = [
+ "ENABLE_ARM_CFI_TABLE=false",
+ "IOS_STACK_PROFILER_ENABLED=true",
+ "USE_ANDROID_UNWINDER_V2=false",
+ ]
+}
+
+buildflag_header("rust_buildflags") {
+ header = "base/rust_buildflags.h"
+ flags = [
+ "BUILD_RUST_JSON_READER=false",
+ "BUILD_RUST_BASE_CONVERSIONS=false",
+ ]
+}
+
+buildflag_header("synchronization_buildflags") {
+ header = "base/synchronization/synchronization_buildflags.h"
+ flags = [ "ENABLE_MUTEX_PRIORITY_INHERITANCE=false" ]
+}
+
+buildflag_header("tracing_buildflags") {
+ header = "base/tracing_buildflags.h"
+ flags = [
+ "ENABLE_BASE_TRACING=true",
+ "USE_PERFETTO_CLIENT_LIBRARY=true",
+ "USE_PERFETTO_TRACE_PROCESSOR=false",
+
+ # "OPTIONAL_TRACE_EVENTS_ENABLED=",
+ ]
+}
+
+buildflag_header("protected_memory_buildflags") {
+ header = "base/memory/protected_memory_buildflags.h"
+ flags = [
+ "PROTECTED_MEMORY_ENABLED=false"
+ ]
+}
+
+protozero_library("tracing_protozero") {
+ proto_in_dir = "base/tracing/protos"
+ proto_out_dir = "include/base/tracing/protos"
+ sources = [ "base/tracing/protos/chrome_track_event.proto" ]
+}
+
+libbase_sublibs = [
+ {
+ name = "base-core"
+ deps = [ ":tracing_protozero" ]
+ libs = [
+ "dl",
+ "double-conversion",
+ "pthread",
+ "rt",
+ "modp_b64",
+ ]
+ pkg_deps = [
+ "absl",
+ "glib-2.0",
+ "libevent",
+ "perfetto",
+ ]
+ configs = [
+ ":base_core_config",
+ ":base_export_config",
+ ]
+ sources = [
+ "base/allocator/partition_allocator/src/partition_alloc/oom.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/oom_callback.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/check.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/debug/alias.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/debug/stack_trace_linux.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/debug/stack_trace_posix.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/log_message.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/logging.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/memory/page_size_posix.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/posix/safe_strerror.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/strings/cstring_builder.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/strings/safe_sprintf.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/strings/string_util.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/strings/stringprintf.cc",
+ "base/at_exit.cc",
+ "base/barrier_closure.cc",
+ "base/base64.cc",
+ "base/base64url.cc",
+ "base/base_switches.cc",
+ "base/callback_list.cc",
+ "base/check.cc",
+ "base/check_is_test.cc",
+ "base/check_op.cc",
+ "base/command_line.cc",
+ "base/containers/intrusive_heap.cc",
+ "base/containers/linked_list.cc",
+ "base/cpu.cc",
+ "base/cpu_reduction_experiment.cc",
+ "base/debug/alias.cc",
+ "base/debug/crash_logging.cc",
+ "base/debug/debugger.cc",
+ "base/debug/debugger_posix.cc",
+ "base/debug/dump_without_crashing.cc",
+ "base/debug/elf_reader.cc",
+ "base/debug/stack_trace.cc",
+ "base/debug/stack_trace_posix.cc",
+ "base/debug/task_trace.cc",
+ "base/environment.cc",
+ "base/feature_list.cc",
+ "base/features.cc",
+ "base/file_descriptor_posix.cc",
+ "base/files/file.cc",
+ "base/files/file_descriptor_watcher_posix.cc",
+ "base/files/file_enumerator.cc",
+ "base/files/file_enumerator_posix.cc",
+ "base/files/file_path.cc",
+ "base/files/file_path_watcher.cc",
+ "base/files/file_path_watcher_inotify.cc",
+ "base/files/file_posix.cc",
+ "base/files/file_tracing.cc",
+ "base/files/file_util.cc",
+ "base/files/file_util_posix.cc",
+ "base/files/important_file_writer.cc",
+ "base/files/important_file_writer_cleaner.cc",
+ "base/files/memory_mapped_file.cc",
+ "base/files/memory_mapped_file_posix.cc",
+ "base/files/scoped_file.cc",
+ "base/files/scoped_file_linux.cc",
+ "base/files/scoped_temp_dir.cc",
+ "base/functional/callback_helpers.cc",
+ "base/functional/callback_internal.cc",
+ "base/hash/hash.cc",
+ "base/hash/md5_nacl.cc",
+ "base/hash/sha1_nacl.cc",
+ "base/json/json_file_value_serializer.cc",
+ "base/json/json_parser.cc",
+ "base/json/json_reader.cc",
+ "base/json/json_string_value_serializer.cc",
+ "base/json/json_value_converter.cc",
+ "base/json/json_writer.cc",
+ "base/json/string_escape.cc",
+ "base/json/values_util.cc",
+ "base/lazy_instance_helpers.cc",
+ "base/location.cc",
+ "base/logging.cc",
+ "base/logging_chromeos.cc",
+ "base/memory/aligned_memory.cc",
+ "base/memory/memory_pressure_listener.cc",
+ "base/memory/nonscannable_memory.cc",
+ "base/memory/page_size_posix.cc",
+ "base/memory/platform_shared_memory_handle.cc",
+ "base/memory/platform_shared_memory_mapper_posix.cc",
+ "base/memory/platform_shared_memory_region.cc",
+ "base/memory/platform_shared_memory_region_posix.cc",
+ "base/memory/read_only_shared_memory_region.cc",
+ "base/memory/ref_counted.cc",
+ "base/memory/ref_counted_memory.cc",
+ "base/memory/shared_memory_mapper.cc",
+ "base/memory/shared_memory_mapping.cc",
+ "base/memory/shared_memory_security_policy.cc",
+ "base/memory/shared_memory_tracker.cc",
+ "base/memory/unsafe_shared_memory_region.cc",
+ "base/memory/weak_ptr.cc",
+ "base/memory/writable_shared_memory_region.cc",
+ "base/message_loop/message_pump.cc",
+ "base/message_loop/message_pump_default.cc",
+ "base/message_loop/message_pump_epoll.cc",
+ "base/message_loop/message_pump_glib.cc",
+ "base/message_loop/message_pump_libevent.cc",
+ "base/message_loop/watchable_io_message_pump_posix.cc",
+ "base/message_loop/work_id_provider.cc",
+ "base/metrics/bucket_ranges.cc",
+ "base/metrics/crc32.cc",
+ "base/metrics/dummy_histogram.cc",
+ "base/metrics/field_trial.cc",
+ "base/metrics/field_trial_param_associator.cc",
+ "base/metrics/field_trial_params.cc",
+ "base/metrics/histogram.cc",
+ "base/metrics/histogram_base.cc",
+ "base/metrics/histogram_functions.cc",
+ "base/metrics/histogram_samples.cc",
+ "base/metrics/histogram_snapshot_manager.cc",
+ "base/metrics/metrics_hashes.cc",
+ "base/metrics/persistent_histogram_allocator.cc",
+ "base/metrics/persistent_memory_allocator.cc",
+ "base/metrics/persistent_sample_map.cc",
+ "base/metrics/ranges_manager.cc",
+ "base/metrics/sample_map.cc",
+ "base/metrics/sample_vector.cc",
+ "base/metrics/sparse_histogram.cc",
+ "base/metrics/statistics_recorder.cc",
+ "base/native_library.cc",
+ "base/native_library_posix.cc",
+ "base/observer_list_internal.cc",
+ "base/observer_list_threadsafe.cc",
+ "base/observer_list_types.cc",
+ "base/pending_task.cc",
+ "base/pickle.cc",
+ "base/posix/can_lower_nice_to.cc",
+ "base/posix/file_descriptor_shuffle.cc",
+ "base/posix/global_descriptors.cc",
+ "base/posix/safe_strerror.cc",
+ "base/posix/unix_domain_socket.cc",
+ "base/power_monitor/power_monitor.cc",
+ "base/power_monitor/power_monitor_device_source.cc",
+ "base/power_monitor/power_monitor_device_source_chromeos.cc",
+ "base/power_monitor/power_monitor_source.cc",
+ "base/process/current_process.cc",
+ "base/process/environment_internal.cc",
+ "base/process/internal_linux.cc",
+ "base/process/kill.cc",
+ "base/process/kill_posix.cc",
+ "base/process/launch.cc",
+ "base/process/launch_posix.cc",
+ "base/process/memory.cc",
+ "base/process/memory_linux.cc",
+ "base/process/process_handle.cc",
+ "base/process/process_handle_linux.cc",
+ "base/process/process_handle_posix.cc",
+ "base/process/process_iterator.cc",
+ "base/process/process_iterator_linux.cc",
+ "base/process/process_linux.cc",
+ "base/process/process_metrics.cc",
+ "base/process/process_metrics_linux.cc",
+ "base/process/process_metrics_posix.cc",
+ "base/process/process_posix.cc",
+ "base/profiler/frame.cc",
+ "base/profiler/metadata_recorder.cc",
+ "base/profiler/module_cache.cc",
+ "base/profiler/module_cache_posix.cc",
+ "base/profiler/sample_metadata.cc",
+ "base/profiler/stack_buffer.cc",
+ "base/profiler/stack_copier.cc",
+ "base/profiler/stack_copier_signal.cc",
+ "base/profiler/stack_sampler.cc",
+ "base/profiler/stack_sampler_posix.cc",
+ "base/profiler/stack_sampling_profiler.cc",
+ "base/profiler/thread_delegate_posix.cc",
+ "base/profiler/unwinder.cc",
+ "base/rand_util.cc",
+ "base/rand_util_posix.cc",
+ "base/run_loop.cc",
+ "base/scoped_native_library.cc",
+ "base/sequence_checker.cc",
+ "base/sequence_checker_impl.cc",
+ "base/sequence_token.cc",
+ "base/strings/escape.cc",
+ "base/strings/pattern.cc",
+ "base/strings/safe_sprintf.cc",
+ "base/strings/strcat.cc",
+ "base/strings/string_number_conversions.cc",
+ "base/strings/string_split.cc",
+ "base/strings/string_util.cc",
+ "base/strings/string_util_constants.cc",
+ "base/strings/stringprintf.cc",
+ "base/strings/sys_string_conversions_posix.cc",
+ "base/strings/utf_offset_string_conversions.cc",
+ "base/strings/utf_ostream_operators.cc",
+ "base/strings/utf_string_conversion_utils.cc",
+ "base/strings/utf_string_conversions.cc",
+ "base/sync_socket.cc",
+ "base/sync_socket_posix.cc",
+ "base/synchronization/atomic_flag.cc",
+ "base/synchronization/condition_variable_posix.cc",
+ "base/synchronization/lock.cc",
+ "base/synchronization/lock_impl_posix.cc",
+ "base/synchronization/waitable_event.cc",
+ "base/synchronization/waitable_event_posix.cc",
+ "base/synchronization/waitable_event_watcher_posix.cc",
+ "base/system/sys_info.cc",
+ "base/system/sys_info_chromeos.cc",
+ "base/system/sys_info_linux.cc",
+ "base/system/sys_info_posix.cc",
+ "base/task/cancelable_task_tracker.cc",
+ "base/task/common/checked_lock_impl.cc",
+ "base/task/common/lazy_now.cc",
+ "base/task/common/operations_controller.cc",
+ "base/task/common/scoped_defer_task_posting.cc",
+ "base/task/common/task_annotator.cc",
+ "base/task/current_thread.cc",
+ "base/task/default_delayed_task_handle_delegate.cc",
+ "base/task/delayed_task_handle.cc",
+ "base/task/lazy_thread_pool_task_runner.cc",
+ "base/task/post_job.cc",
+ "base/task/scoped_set_task_priority_for_current_thread.cc",
+ "base/task/sequence_manager/associated_thread_id.cc",
+ "base/task/sequence_manager/atomic_flag_set.cc",
+ "base/task/sequence_manager/delayed_task_handle_delegate.cc",
+ "base/task/sequence_manager/enqueue_order_generator.cc",
+ "base/task/sequence_manager/fence.cc",
+ "base/task/sequence_manager/sequence_manager.cc",
+ "base/task/sequence_manager/sequence_manager_impl.cc",
+ "base/task/sequence_manager/sequenced_task_source.cc",
+ "base/task/sequence_manager/task_order.cc",
+ "base/task/sequence_manager/task_queue.cc",
+ "base/task/sequence_manager/task_queue_impl.cc",
+ "base/task/sequence_manager/task_queue_selector.cc",
+ "base/task/sequence_manager/tasks.cc",
+ "base/task/sequence_manager/thread_controller.cc",
+ "base/task/sequence_manager/thread_controller_impl.cc",
+ "base/task/sequence_manager/thread_controller_power_monitor.cc",
+ "base/task/sequence_manager/thread_controller_with_message_pump_impl.cc",
+ "base/task/sequence_manager/time_domain.cc",
+ "base/task/sequence_manager/wake_up_queue.cc",
+ "base/task/sequence_manager/work_deduplicator.cc",
+ "base/task/sequence_manager/work_queue.cc",
+ "base/task/sequence_manager/work_queue_sets.cc",
+ "base/task/sequence_manager/work_tracker.cc",
+ "base/task/sequenced_task_runner.cc",
+ "base/task/single_thread_task_executor.cc",
+ "base/task/single_thread_task_runner.cc",
+ "base/task/task_features.cc",
+ "base/task/task_runner.cc",
+ "base/task/task_traits.cc",
+ "base/task/thread_pool.cc",
+ "base/task/thread_pool/delayed_task_manager.cc",
+ "base/task/thread_pool/environment_config.cc",
+ "base/task/thread_pool/job_task_source.cc",
+ "base/task/thread_pool/pooled_parallel_task_runner.cc",
+ "base/task/thread_pool/pooled_sequenced_task_runner.cc",
+ "base/task/thread_pool/pooled_single_thread_task_runner_manager.cc",
+ "base/task/thread_pool/pooled_task_runner_delegate.cc",
+ "base/task/thread_pool/priority_queue.cc",
+ "base/task/thread_pool/semaphore/semaphore_posix.cc",
+ "base/task/thread_pool/sequence.cc",
+ "base/task/thread_pool/service_thread.cc",
+ "base/task/thread_pool/task.cc",
+ "base/task/thread_pool/task_source.cc",
+ "base/task/thread_pool/task_source_sort_key.cc",
+ "base/task/thread_pool/task_tracker.cc",
+ "base/task/thread_pool/thread_group.cc",
+ "base/task/thread_pool/thread_group_impl.cc",
+ "base/task/thread_pool/thread_group_semaphore.cc",
+ "base/task/thread_pool/thread_group_worker_delegate.cc",
+ "base/task/thread_pool/thread_pool_impl.cc",
+ "base/task/thread_pool/thread_pool_instance.cc",
+ "base/task/thread_pool/worker_thread.cc",
+ "base/task/thread_pool/worker_thread_semaphore.cc",
+ "base/task/thread_pool/worker_thread_set.cc",
+ "base/task/thread_pool/worker_thread_waitable_event.cc",
+ "base/third_party/cityhash/city.cc",
+ "base/third_party/nspr/prtime.cc",
+ "base/third_party/superfasthash/superfasthash.c",
+ "base/threading/hang_watcher.cc",
+ "base/threading/platform_thread.cc",
+ "base/threading/platform_thread_cros.cc",
+ "base/threading/platform_thread_internal_posix.cc",
+ "base/threading/platform_thread_linux.cc",
+ "base/threading/platform_thread_linux_base.cc",
+ "base/threading/platform_thread_posix.cc",
+ "base/threading/platform_thread_ref.cc",
+ "base/threading/post_task_and_reply_impl.cc",
+ "base/threading/scoped_blocking_call.cc",
+ "base/threading/scoped_blocking_call_internal.cc",
+ "base/threading/sequence_local_storage_map.cc",
+ "base/threading/sequence_local_storage_slot.cc",
+ "base/threading/simple_thread.cc",
+ "base/threading/thread.cc",
+ "base/threading/thread_checker.cc",
+ "base/threading/thread_checker_impl.cc",
+ "base/threading/thread_collision_warner.cc",
+ "base/threading/thread_id_name_manager.cc",
+ "base/threading/thread_local_storage.cc",
+ "base/threading/thread_local_storage_posix.cc",
+ "base/threading/thread_restrictions.cc",
+ "base/threading/thread_type_delegate.cc",
+ "base/threading/watchdog.cc",
+ "base/time/clock.cc",
+ "base/time/default_clock.cc",
+ "base/time/default_tick_clock.cc",
+ "base/time/tick_clock.cc",
+ "base/time/time.cc",
+ "base/time/time_conversion_posix.cc",
+ "base/time/time_delta_from_string.cc",
+ "base/time/time_exploded_posix.cc",
+ "base/time/time_now_posix.cc",
+ "base/time/time_override.cc",
+ "base/timer/elapsed_timer.cc",
+ "base/timer/lap_timer.cc",
+ "base/timer/timer.cc",
+ "base/timer/wall_clock_timer.cc",
+ "base/token.cc",
+ "base/trace_event/category_registry.cc",
+ "base/trace_event/heap_profiler_allocation_context_tracker.cc",
+ "base/trace_event/interned_args_helper.cc",
+ "base/trace_event/malloc_dump_provider.cc",
+ "base/trace_event/memory_allocator_dump.cc",
+ "base/trace_event/memory_allocator_dump_guid.cc",
+ "base/trace_event/memory_dump_manager.cc",
+ "base/trace_event/memory_dump_provider_info.cc",
+ "base/trace_event/memory_dump_request_args.cc",
+ "base/trace_event/memory_dump_scheduler.cc",
+ "base/trace_event/memory_infra_background_allowlist.cc",
+ "base/trace_event/memory_pressure_level_proto.cc",
+ "base/trace_event/memory_usage_estimator.cc",
+ "base/trace_event/process_memory_dump.cc",
+ "base/trace_event/trace_arguments.cc",
+ "base/trace_event/trace_buffer.cc",
+ "base/trace_event/trace_config.cc",
+ "base/trace_event/trace_config_category_filter.cc",
+ "base/trace_event/trace_event_impl.cc",
+ "base/trace_event/trace_event_memory_overhead.cc",
+ "base/trace_event/trace_id_helper.cc",
+ "base/trace_event/trace_log.cc",
+ "base/trace_event/trace_log_constants.cc",
+ "base/trace_event/traced_value.cc",
+ "base/trace_event/typed_macros_internal.cc",
+ "base/unguessable_token.cc",
+ "base/uuid.cc",
+ "base/value_iterators.cc",
+ "base/values.cc",
+ "base/version.cc",
+ "base/vlog.cc",
+ "dump_without_crashing.cc",
+ ]
+
+ if (use_allocator_shim) {
+ sources += [
+ "base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.cc",
+ "base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_glibc.cc",
+ ]
+ }
+
+ # ARM and X86 doesn't have implementations for frame pointer unwinder.
+ # ARM and X86 has stack profiler disabled.
+ if (current_cpu == "x64" || current_cpu == "arm64") {
+ sources += [
+ "base/profiler/frame_pointer_unwinder.cc",
+ ]
+ }
+ },
+
+ {
+ name = "base-policy"
+ deps = [ ":base-core" ]
+ libs = [ "re2" ]
+ configs = [ ":policy_export_config" ]
+ sources = [
+ "components/policy/core/common/json_schema_constants.cc",
+ "components/policy/core/common/registry_dict.cc",
+ "components/policy/core/common/schema.cc",
+ ]
+ },
+
+ {
+ name = "base-base_test_support"
+ deps = [ ":tracing_protozero" ]
+ testonly = true
+ sources = [
+ "base/test/metrics/histogram_tester.cc",
+ "base/test/mock_entropy_provider.cc",
+ "base/test/mock_log.cc",
+ "base/test/power_monitor_test.cc",
+ "base/test/scoped_chromeos_version_info.cc",
+ "base/test/scoped_command_line.cc",
+ "base/test/scoped_feature_list.cc",
+ "base/test/scoped_run_loop_timeout.cc",
+ "base/test/simple_test_clock.cc",
+ "base/test/simple_test_tick_clock.cc",
+ "base/test/task_environment.cc",
+ "base/test/test_file_util.cc",
+ "base/test/test_file_util_linux.cc",
+ "base/test/test_file_util_posix.cc",
+ "base/test/test_mock_time_task_runner.cc",
+ "base/test/test_pending_task.cc",
+ "base/test/test_simple_task_runner.cc",
+ "base/test/test_switches.cc",
+ "base/test/test_timeouts.cc",
+ "base/timer/mock_timer.cc",
+ ]
+ },
+]
+
+if (use.crypto) {
+ libbase_sublibs += [
+ {
+ name = "base-crypto"
+ deps = [ ":base-core" ]
+ libs = [
+ "dl",
+ "pthread",
+ ]
+ pkg_deps = [
+ "nss",
+ "openssl",
+ ]
+ configs = [ ":crypto_export_config" ]
+ sources = [
+ "crypto/hmac.cc",
+ "crypto/hmac_nss.cc",
+
+ # Added to libchrome only (not upstream) to support OpenSSL 1.1 API
+ "crypto/libcrypto-compat.c",
+ "crypto/nss_key_util.cc",
+ "crypto/nss_util.cc",
+ "crypto/openssl_util.cc",
+ "crypto/random.cc",
+ "crypto/rsa_private_key.cc",
+ "crypto/rsa_private_key_nss.cc",
+ "crypto/scoped_test_nss_db.cc",
+ "crypto/secure_hash.cc",
+ "crypto/secure_util.cc",
+ "crypto/sha2.cc",
+ "crypto/signature_creator_nss.cc",
+ "crypto/signature_verifier_nss.cc",
+ "crypto/symmetric_key_nss.cc",
+ "crypto/third_party/nss/rsawrapr.c",
+ "crypto/third_party/nss/sha512.cc",
+ ]
+ },
+ ]
+}
+
+if (use.dbus) {
+ libbase_sublibs += [
+ {
+ name = "base-dbus"
+ deps = [ ":base-core" ]
+ pkg_deps = [
+ "absl",
+ "dbus-1",
+ ]
+ if (use.fuzzer) {
+ pkg_deps += [ "protobuf" ]
+ } else {
+ pkg_deps += [ "protobuf-lite" ]
+ }
+ configs = [ ":dbus_export_config" ]
+ sources = [
+ "dbus/bus.cc",
+ "dbus/dbus_statistics.cc",
+ "dbus/error.cc",
+ "dbus/exported_object.cc",
+ "dbus/message.cc",
+ "dbus/object_manager.cc",
+ "dbus/object_path.cc",
+ "dbus/object_proxy.cc",
+ "dbus/property.cc",
+ "dbus/scoped_dbus_error.cc",
+ "dbus/string_util.cc",
+ "dbus/util.cc",
+ "dbus/values_util.cc",
+ ]
+ },
+
+ {
+ name = "base-dbus_test_support"
+ testonly = true
+ pkg_deps = [ "dbus-1" ]
+ if (use.fuzzer) {
+ pkg_deps += [ "protobuf" ]
+ } else {
+ pkg_deps += [ "protobuf-lite" ]
+ }
+ sources = [
+ "dbus/mock_bus.cc",
+ "dbus/mock_exported_object.cc",
+ "dbus/mock_object_manager.cc",
+ "dbus/mock_object_proxy.cc",
+ ]
+ },
+ ]
+}
+
+# Generate static/shared libraries.
+foreach(attr, libbase_sublibs) {
+ if (defined(attr.pkg_deps)) {
+ # If it depends on external packages, introduces -pkg-config config.
+ pkg_config(attr.name + "-pkg-config") {
+ pkg_deps = attr.pkg_deps
+ }
+ }
+
+ if (defined(attr.testonly) && attr.testonly) {
+ buildtype = "static_library"
+ } else {
+ buildtype = "shared_library"
+ }
+ target(buildtype, attr.name) {
+ sources = attr.sources
+ deps = [ ":all_buildflags" ]
+ if (defined(attr.deps)) {
+ deps += attr.deps
+ }
+
+ if (defined(attr.libs)) {
+ libs = attr.libs
+ }
+
+ if (defined(attr.pkg_deps)) {
+ configs += [ ":" + attr.name + "-pkg-config" ]
+ }
+ configs += [ ":libchrome_config" ]
+ if (buildtype == "static_library") {
+ configs -= [ "//common-mk:use_thin_archive" ]
+ configs += [ "//common-mk:nouse_thin_archive" ]
+ }
+ if (defined(attr.configs)) {
+ configs += attr.configs
+ }
+ }
+}
+
+action("base") {
+ deps = []
+ foreach(attr, libbase_sublibs) {
+ if (!defined(attr.testonly) || !attr.testonly) {
+ deps += [ ":" + attr.name ]
+ }
+ }
+
+ script = "//common-mk/write_args.py"
+ outputs = [ "${root_out_dir}/lib/lib${target_name}.so" ]
+ args = [ "--output" ] + outputs + [ "--" ] + [
+ "GROUP",
+ "(",
+ "AS_NEEDED",
+ "(",
+ ]
+ foreach(attr, libbase_sublibs) {
+ if (!defined(attr.testonly) || !attr.testonly) {
+ args += [ "-l" + attr.name ]
+ }
+ }
+ args += [
+ ")",
+ ")",
+ ]
+}
+
+libchrome_exported_cflags = [
+ "-I/usr/include/libchrome",
+ "-Wno-unused-local-typedefs",
+ "-DBASE_VER=${libchrome_basever}",
+ "-DBASE_USE_PERFETTO_CLIENT_LIBRARY",
+ "-DPERFETTO_ENABLE_LEGACY_TRACE_EVENTS=1",
+]
+
+if (use.asan) {
+ libchrome_exported_cflags += [
+ "-DLEAK_SANITIZER",
+ "-DDISABLE_ALLOCATOR_SANITIZER",
+ ]
+}
+
+generate_pkg_config("libchrome") {
+ deps = [ ":base" ]
+ description = "chrome base library"
+ version = "${libchrome_basever}"
+ requires_private = []
+ foreach(attr, libbase_sublibs) {
+ if ((!defined(attr.testonly) || !attr.testonly) && defined(attr.pkg_deps)) {
+ requires_private += attr.pkg_deps
+ }
+ }
+
+ # base/synchronization/lock_impl.h has function inlined that uses pthread.
+ libs = [
+ "-lbase",
+ "-lpthread",
+ ]
+ libs_private = []
+ foreach(attr, libbase_sublibs) {
+ if (!defined(attr.testonly) || !attr.testonly) {
+ libs_private += [ "-l" + attr.name ]
+ if (defined(attr.libs)) {
+ foreach(lib, attr.libs) {
+ libs_private += [ "-l" + lib ]
+ }
+ }
+ }
+ }
+ cflags = libchrome_exported_cflags
+}
+
+action("base-test") {
+ deps = []
+ foreach(attr, libbase_sublibs) {
+ if (defined(attr.testonly) && attr.testonly) {
+ deps += [ ":" + attr.name ]
+ }
+ }
+
+ script = "//common-mk/write_args.py"
+ outputs = [ "${root_out_dir}/lib${target_name}.a" ]
+ args = [ "--output" ] + outputs + [ "--" ] + [
+ "GROUP",
+ "(",
+ "AS_NEEDED",
+ "(",
+ ]
+ foreach(attr, libbase_sublibs) {
+ if (defined(attr.testonly) && attr.testonly) {
+ args += [ "-l" + attr.name ]
+ }
+ }
+ args += [
+ ")",
+ ")",
+ ]
+}
+
+generate_pkg_config("libchrome-test") {
+ deps = [ ":base-test" ]
+ description = "chrome base test library"
+ version = "${libchrome_basever}"
+ requires_private = []
+ foreach(attr, libbase_sublibs) {
+ if (defined(attr.testonly) && attr.testonly && defined(attr.pkg_deps)) {
+ requires_private += attr.pkg_deps
+ }
+ }
+ libs = [ "-lbase-test" ]
+ libs_private = []
+ foreach(attr, libbase_sublibs) {
+ if (defined(attr.testonly) && attr.testonly) {
+ libs_private += [ "-l" + attr.name ]
+ if (defined(attr.libs)) {
+ libs_private += [ "-l" + lib ]
+ }
+ }
+ }
+ cflags = libchrome_exported_cflags
+}
+
+if (use.mojo) {
+ generate_mojom_type_mappings("mojom_type_mappings") {
+ mojom_type_mappings_generator =
+ "libchrome_tools/mojom_generate_type_mappings.py"
+ sources = [
+ "mojo/public/cpp/base/file.typemap",
+ "mojo/public/cpp/base/file_error.typemap",
+ "mojo/public/cpp/base/file_info.typemap",
+ "mojo/public/cpp/base/file_path.typemap",
+ "mojo/public/cpp/base/memory_allocator_dump_cross_process_uid.typemap",
+ "mojo/public/cpp/base/process_id.typemap",
+ "mojo/public/cpp/base/read_only_buffer.typemap",
+ "mojo/public/cpp/base/shared_memory.typemap",
+ "mojo/public/cpp/base/text_direction.typemap",
+ "mojo/public/cpp/base/thread_priority.typemap",
+ "mojo/public/cpp/base/time.typemap",
+ "mojo/public/cpp/base/unguessable_token.typemap",
+ "mojo/public/cpp/base/values.typemap",
+ ]
+ }
+ generate_mojom_bindings_gen("mojom_bindings_gen") {
+ mojom_bindings_generator =
+ "mojo/public/tools/bindings/mojom_bindings_generator.py"
+ mojom_parser = "mojo/public/tools/mojom/mojom_parser.py"
+
+ # TODO(fqj): revisit typemaps after uprev.
+ # typemaps = get_target_outputs(":mojom_type_mappings")
+ sources = [
+ "ipc/ipc.mojom",
+
+ # TODO(fqj): Revisit these 3 files after uprev.
+ "mojo/public/interfaces/bindings/interface_control_messages.mojom",
+ "mojo/public/interfaces/bindings/native_struct.mojom",
+ "mojo/public/interfaces/bindings/pipe_control_messages.mojom",
+ "mojo/public/mojom/base/file.mojom",
+ "mojo/public/mojom/base/file_error.mojom",
+ "mojo/public/mojom/base/file_info.mojom",
+ "mojo/public/mojom/base/file_path.mojom",
+ "mojo/public/mojom/base/generic_pending_associated_receiver.mojom",
+ "mojo/public/mojom/base/generic_pending_receiver.mojom",
+ "mojo/public/mojom/base/memory_allocator_dump_cross_process_uid.mojom",
+ "mojo/public/mojom/base/process_id.mojom",
+ "mojo/public/mojom/base/read_only_buffer.mojom",
+ "mojo/public/mojom/base/shared_memory.mojom",
+ "mojo/public/mojom/base/text_direction.mojom",
+ "mojo/public/mojom/base/thread_type.mojom",
+ "mojo/public/mojom/base/time.mojom",
+ "mojo/public/mojom/base/unguessable_token.mojom",
+ "mojo/public/mojom/base/values.mojom",
+ "ui/gfx/geometry/mojom/geometry.mojom",
+ "ui/gfx/range/mojom/range.mojom",
+ ]
+ }
+
+ # TODO(fqj): Revisit these 3 files after uprev.
+ # generate_mojom_bindings_gen("mojom_bindings_native_gen") {
+ # mojom_bindings_generator =
+ # "mojo/public/tools/bindings/mojom_bindings_generator.py"
+ # mojom_parser = "mojo/public/tools/mojom/mojom_parser.py"
+ # sources = [
+ # ]
+ # disallow_native_types = true
+ # disallow_interfaces = true
+ # }
+
+ # Probably we should consider build libmojo as a part of libchrome.
+ # crbug.com/924035.
+ shared_library("mojo") {
+ deps = [
+ ":all_buildflags",
+ ":base-core",
+ ":base-crypto",
+ ":mojom_bindings_gen",
+ ":mojom_bindings_gen",
+
+ # ":mojom_bindings_native_gen",
+ # ":mojom_type_mappings",
+ ]
+ libs = [ "pthread" ]
+
+ # TODO(hidehiko): Consolidate with build_config.h.
+ configs += [
+ ":libchrome_config",
+ ":mojo_export_config",
+ "//common-mk:visibility_default",
+ ]
+ sources =
+ [
+ "ipc/ipc_message.cc",
+ "ipc/ipc_message_attachment_set.cc",
+ "ipc/native_handle_type_converters.cc",
+ "mojo/core/atomic_flag.cc",
+ "mojo/core/broker_host.cc",
+ "mojo/core/broker_posix.cc",
+ "mojo/core/channel.cc",
+ "mojo/core/channel_linux.cc",
+ "mojo/core/channel_posix.cc",
+ "mojo/core/configuration.cc",
+ "mojo/core/connection_params.cc",
+ "mojo/core/core.cc",
+ "mojo/core/core_ipcz.cc",
+ "mojo/core/data_pipe_consumer_dispatcher.cc",
+ "mojo/core/data_pipe_control_message.cc",
+ "mojo/core/data_pipe_producer_dispatcher.cc",
+ "mojo/core/dispatcher.cc",
+ "mojo/core/embedder/embedder.cc",
+ "mojo/core/embedder/features.cc",
+ "mojo/core/embedder/scoped_ipc_support.cc",
+ "mojo/core/entrypoints.cc",
+ "mojo/core/handle_table.cc",
+ "mojo/core/invitation_dispatcher.cc",
+ "mojo/core/ipcz_api.cc",
+ "mojo/core/ipcz_driver/base_shared_memory_service.cc",
+ "mojo/core/ipcz_driver/data_pipe.cc",
+ "mojo/core/ipcz_driver/driver.cc",
+ "mojo/core/ipcz_driver/invitation.cc",
+ "mojo/core/ipcz_driver/mojo_message.cc",
+ "mojo/core/ipcz_driver/mojo_trap.cc",
+ "mojo/core/ipcz_driver/object.cc",
+ "mojo/core/ipcz_driver/ring_buffer.cc",
+ "mojo/core/ipcz_driver/shared_buffer.cc",
+ "mojo/core/ipcz_driver/shared_buffer_mapping.cc",
+ "mojo/core/ipcz_driver/transmissible_platform_handle.cc",
+ "mojo/core/ipcz_driver/transport.cc",
+ "mojo/core/ipcz_driver/wrapped_platform_handle.cc",
+ "mojo/core/message_pipe_dispatcher.cc",
+ "mojo/core/mojo_core.cc",
+ "mojo/core/node_channel.cc",
+ "mojo/core/node_controller.cc",
+ "mojo/core/platform_handle_dispatcher.cc",
+ "mojo/core/platform_handle_in_transit.cc",
+ "mojo/core/platform_handle_utils.cc",
+ "mojo/core/platform_shared_memory_mapping.cc",
+ "mojo/core/ports/event.cc",
+ "mojo/core/ports/message_queue.cc",
+ "mojo/core/ports/name.cc",
+ "mojo/core/ports/node.cc",
+ "mojo/core/ports/port.cc",
+ "mojo/core/ports/port_locker.cc",
+ "mojo/core/ports/port_ref.cc",
+ "mojo/core/ports/user_message.cc",
+ "mojo/core/request_context.cc",
+ "mojo/core/scoped_ipcz_handle.cc",
+ "mojo/core/shared_buffer_dispatcher.cc",
+ "mojo/core/user_message_impl.cc",
+ "mojo/core/watch.cc",
+ "mojo/core/watcher_dispatcher.cc",
+ "mojo/core/watcher_set.cc",
+ "mojo/public/c/system/thunks.cc",
+ "mojo/public/cpp/bindings/async_flusher.cc",
+ "mojo/public/cpp/bindings/connection_group.cc",
+ "mojo/public/cpp/bindings/features.cc",
+ "mojo/public/cpp/bindings/lib/array_internal.cc",
+ "mojo/public/cpp/bindings/lib/associated_group.cc",
+ "mojo/public/cpp/bindings/lib/associated_group_controller.cc",
+ "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc",
+ "mojo/public/cpp/bindings/lib/associated_receiver.cc",
+ "mojo/public/cpp/bindings/lib/binding_state.cc",
+ "mojo/public/cpp/bindings/lib/buffer.cc",
+ "mojo/public/cpp/bindings/lib/connector.cc",
+ "mojo/public/cpp/bindings/lib/control_message_handler.cc",
+ "mojo/public/cpp/bindings/lib/control_message_proxy.cc",
+ "mojo/public/cpp/bindings/lib/generated_code_util.cc",
+ "mojo/public/cpp/bindings/lib/handle_serialization.cc",
+ "mojo/public/cpp/bindings/lib/interface_endpoint_client.cc",
+ "mojo/public/cpp/bindings/lib/interface_ptr_state.cc",
+ "mojo/public/cpp/bindings/lib/message.cc",
+ "mojo/public/cpp/bindings/lib/message_dispatcher.cc",
+ "mojo/public/cpp/bindings/lib/message_header_validator.cc",
+ "mojo/public/cpp/bindings/lib/message_internal.cc",
+ "mojo/public/cpp/bindings/lib/multiplex_router.cc",
+ "mojo/public/cpp/bindings/lib/pending_receiver_state.cc",
+ "mojo/public/cpp/bindings/lib/pending_remote_state.cc",
+ "mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc",
+ "mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc",
+ "mojo/public/cpp/bindings/lib/proxy_to_responder.cc",
+ "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc",
+ "mojo/public/cpp/bindings/lib/send_message_helper.cc",
+ "mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc",
+ "mojo/public/cpp/bindings/lib/sync_call_restrictions.cc",
+ "mojo/public/cpp/bindings/lib/sync_event_watcher.cc",
+ "mojo/public/cpp/bindings/lib/sync_handle_registry.cc",
+ "mojo/public/cpp/bindings/lib/sync_handle_watcher.cc",
+ "mojo/public/cpp/bindings/lib/task_runner_helper.cc",
+ "mojo/public/cpp/bindings/lib/thread_safe_forwarder_base.cc",
+ "mojo/public/cpp/bindings/lib/validation_context.cc",
+ "mojo/public/cpp/bindings/lib/validation_errors.cc",
+ "mojo/public/cpp/bindings/lib/validation_util.cc",
+ "mojo/public/cpp/bindings/pending_flush.cc",
+ "mojo/public/cpp/bindings/receiver_set.cc",
+ "mojo/public/cpp/bindings/urgent_message_scope.cc",
+ "mojo/public/cpp/platform/platform_channel.cc",
+ "mojo/public/cpp/platform/platform_channel_endpoint.cc",
+ "mojo/public/cpp/platform/platform_channel_server.cc",
+ "mojo/public/cpp/platform/platform_channel_server_endpoint.cc",
+ "mojo/public/cpp/platform/platform_channel_server_posix.cc",
+ "mojo/public/cpp/platform/platform_handle.cc",
+ "mojo/public/cpp/platform/socket_utils_posix.cc",
+ "mojo/public/cpp/system/handle_signal_tracker.cc",
+ "mojo/public/cpp/system/buffer.cc",
+ "mojo/public/cpp/system/invitation.cc",
+ "mojo/public/cpp/system/isolated_connection.cc",
+ "mojo/public/cpp/system/platform_handle.cc",
+ "mojo/public/cpp/system/simple_watcher.cc",
+ "mojo/public/cpp/system/trap.cc",
+ "mojo/public/cpp/system/wait.cc",
+ "mojo/public/cpp/system/wait_set.cc",
+ ] + get_target_outputs(":mojom_bindings_gen") # +
+
+ #get_target_outputs(":mojom_bindings_native_gen")
+
+ if (use.asan || use.fuzzer || use.msan || use.ubsan) {
+ sources += [
+ "ipc/ipc_message_attachment.cc",
+ "ipc/ipc_mojo_handle_attachment.cc",
+ "ipc/ipc_platform_file_attachment_posix.cc",
+ ]
+ }
+ }
+
+ generate_pkg_config("libmojo") {
+ deps = [ ":mojo" ]
+ description = "Chrome Mojo IPC library"
+ version = "${libchrome_basever}"
+ libs = [ "-lmojo" ]
+ cflags = [
+ "-I/usr/include/libchrome",
+ "-Wno-cast-qual",
+ "-Wno-cast-align",
+ ]
+ }
+}
+
+if (use.test) {
+ executable("optional_unittests") {
+ sources = [
+ "base/test/gtest_util.cc",
+ "base/test/values_test_util.cc",
+ "base/types/optional_unittest.cc",
+ ]
+ configs += [
+ "//common-mk:test",
+ ":libchrome_config",
+ ]
+ libs = [ "gtest_main" ]
+ deps = [
+ ":base-core",
+ "//common-mk/testrunner:testrunner",
+ ]
+ }
+}
+
+install_config("install_basever") {
+ sources = [ "BASE_VER" ]
+ install_path = "/usr/share/libchrome"
+}
+
+install_config("install_header") {
+ sources = []
+ sources += [
+ "base/*.h",
+ "base/allocator/*.h",
+ "base/allocator/partition_allocator/src/partition_alloc/*.h",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/*.h",
+ "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/augmentations/*.h",
+ "base/allocator/partition_allocator/src/partition_alloc/pointers/*.h",
+ "base/allocator/partition_allocator/src/partition_alloc/starscan/*.h",
+ "base/containers/*.h",
+ "base/debug/*.h",
+ "base/files/*.h",
+ "base/functional/*.h",
+ "base/hash/*.h",
+ "base/i18n/*.h",
+ "base/json/*.h",
+ "base/macros/*.h",
+ "base/memory/*.h",
+ "base/message_loop/*.h",
+ "base/metrics/*.h",
+ "base/numerics/*.h",
+ "base/posix/*.h",
+ "base/power_monitor/*.h",
+ "base/process/*.h",
+ "base/profiler/*.h",
+ "base/ranges/*.h",
+ "base/strings/*.h",
+ "base/synchronization/*.h",
+ "base/system/*.h",
+ "base/task/*.h",
+ "base/task/common/*.h",
+ "base/task/sequence_manager/*.h",
+ "base/task/thread_pool/*.h",
+ "base/third_party/icu/*.h",
+ "base/third_party/nspr/*.h",
+ "base/third_party/valgrind/*.h",
+ "base/threading/*.h",
+ "base/time/*.h",
+ "base/timer/*.h",
+ "base/trace_event/*.h",
+ "base/trace_event/common/*.h",
+ "base/types/*.h",
+ "build/*.h",
+ "components/policy/*.h",
+ "components/policy/core/common/*.h",
+ "testing/gmock/include/gmock/*.h",
+ "testing/gtest/include/gtest/*.h",
+ ]
+ if (use.dbus) {
+ sources += [ "dbus/*.h" ]
+ }
+ if (use.mojo) {
+ sources += [
+ "ipc/*.h",
+ "mojo/core/*.h",
+ "mojo/core/embedder/*.h",
+ "mojo/core/ports/*.h",
+ "mojo/public/c/system/*.h",
+ "mojo/public/cpp/base/*.h",
+ "mojo/public/cpp/bindings/*.h",
+ "mojo/public/cpp/bindings/lib/*.h",
+ "mojo/public/cpp/platform/*.h",
+ "mojo/public/cpp/system/*.h",
+ ]
+ }
+ sources += [
+ "base/test/allow_check_is_test_to_be_called.h",
+ "base/test/bind.h",
+ "base/test/gmock_callback_support.h",
+ "base/test/metrics/histogram_tester.h",
+ "base/test/mock_callback.h",
+ "base/test/mock_log.h",
+ "base/test/power_monitor_test.h",
+ "base/test/repeating_test_future.h",
+ "base/test/scoped_chromeos_version_info.h",
+ "base/test/scoped_command_line.h",
+ "base/test/scoped_feature_list.h",
+ "base/test/scoped_logging_settings.h",
+ "base/test/scoped_run_loop_timeout.h",
+ "base/test/scoped_running_on_chromeos.h",
+ "base/test/simple_test_clock.h",
+ "base/test/simple_test_tick_clock.h",
+ "base/test/task_environment.h",
+ "base/test/test_file_util.h",
+ "base/test/test_future.h",
+ "base/test/test_future_internal.h",
+ "base/test/test_mock_time_task_runner.h",
+ "base/test/test_pending_task.h",
+ "base/test/test_switches.h",
+ "base/test/test_timeouts.h",
+ ]
+ sources += [
+ "third_party/abseil-cpp/**/*.h",
+ "third_party/ipcz/**/*.h",
+ "third_party/libevent/*.h",
+ "third_party/perfetto/**/*.h",
+ ]
+ if (use.crypto) {
+ sources += [
+ "crypto/crypto_export.h",
+ "crypto/hmac.h",
+ "crypto/libcrypto-compat.h",
+ "crypto/nss_key_util.h",
+ "crypto/nss_util.h",
+ "crypto/nss_util_internal.h",
+ "crypto/openssl_util.h",
+ "crypto/p224.h",
+ "crypto/p224_spake.h",
+ "crypto/random.h",
+ "crypto/rsa_private_key.h",
+ "crypto/scoped_nss_types.h",
+ "crypto/scoped_openssl_types.h",
+ "crypto/scoped_test_nss_db.h",
+ "crypto/secure_hash.h",
+ "crypto/secure_util.h",
+ "crypto/sha2.h",
+ "crypto/signature_creator.h",
+ "crypto/signature_verifier.h",
+ ]
+ }
+ install_path = "/usr/include/libchrome"
+ glob = true
+ tree_relative_to = "."
+}
+
+install_config("install_mojom_generated") {
+ sources = [
+ "${root_gen_dir}/include/mojo/public/interfaces/bindings/*.h",
+ "${root_gen_dir}/include/mojo/public/mojom/base/*.h",
+ ]
+ glob = true
+ tree_relative_to = "${root_gen_dir}/include"
+ install_path = "/usr/include/libchrome"
+}
+
+install_config("install_buildflag_header") {
+ sources = [
+ "${root_gen_dir}/libchrome/base/**/*buildflags.h",
+ "${root_gen_dir}/libchrome/build/**/*buildflags.h",
+ ]
+ if (use.mojo) {
+ sources += [
+ "${root_gen_dir}/libchrome/ipc/**/*buildflags.h",
+ "${root_gen_dir}/libchrome/mojo/**/*buildflags.h",
+ ]
+ }
+ install_path = "/usr/include/libchrome"
+ glob = true
+ tree_relative_to = "${root_gen_dir}/libchrome"
+}
+
+install_config("install_protozero_generated") {
+ sources = [
+ "${root_gen_dir}/include/base/tracing/protos/chrome_track_event.pbzero.h",
+ ]
+ deps = [ ":tracing_protozero" ]
+ tree_relative_to = "${root_gen_dir}/include"
+ install_path = "/usr/include/libchrome"
+}
diff --git a/DIR_METADATA b/DIR_METADATA
new file mode 100644
index 0000000..5bdaedc
--- /dev/null
+++ b/DIR_METADATA
@@ -0,0 +1,53 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+buganizer {
+ component_id: 656538 # ChromeOS > Software > Eng Velocity > libchrome
+}
+
+team_email: "chromeos-libchrome@google.com"
+
+chromeos {
+ cq {
+ # See go/cros-cq-test-config.
+ source_test_plans {
+ test_plan_starlark_files {
+ host: "chrome-internal.googlesource.com"
+ project: "chromeos/config-internal"
+ path: "test/plans/v2/ctpv1_compatible/legacy_default_tast_hw.star"
+ }
+ test_plan_starlark_files {
+ host: "chrome-internal.googlesource.com"
+ project: "chromeos/config-internal"
+ path: "test/plans/v2/ctpv1_compatible/legacy_default_autotest_hw.star"
+ }
+ test_plan_starlark_files {
+ host: "chrome-internal.googlesource.com"
+ project: "chromeos/config-internal"
+ path: "test/plans/v2/ctpv1_compatible/legacy_default_vm.star"
+ }
+ # Skip testing on developer-tools.
+ path_regexp_excludes: "libchrome_tools/developer-tools/.*"
+ }
+ source_test_plans {
+ test_plan_starlark_files {
+ host: "chrome-internal.googlesource.com"
+ project: "chromeos/config-internal"
+ path: "test/plans/v2/ctpv1_compatible/bvt_tast_cq_each_arch.star"
+ }
+ test_plan_starlark_files {
+ host: "chrome-internal.googlesource.com"
+ project: "chromeos/config-internal"
+ path: "test/plans/v2/ctpv1_compatible/libchrome_cq.star"
+ }
+ path_regexps: "BASE_VER"
+ path_regexps: "libchrome_tools/patches"
+ path_regexps: ".*buildflags.h"
+ }
+ }
+}
diff --git a/MODULE_LICENSE_BSD b/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..15b7060
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..9089385
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,6 @@
+fqj@google.com
+hashimoto@google.com
+hidehiko@google.com
+hscham@chromium.org
+jorgelo@google.com
+chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com # for automated uprevs
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg
new file mode 100644
index 0000000..8a0f3b7
--- /dev/null
+++ b/PRESUBMIT.cfg
@@ -0,0 +1,12 @@
+# Files are verbatim copies of Chromium code base. Disable CrOS license check.
+# Specifically, generated files and files under third_party for mojom tools
+# are using non-chrome standard style. Disable style checks, too.
+[Options]
+ignore_merged_commits: true
+[Hook Scripts]
+check-patches = libchrome_tools/developer-tools/presubmit/check-patches.py --commit ${PRESUBMIT_COMMIT}
+[Hook Overrides]
+cros_license_check: false
+long_line_check: false
+stray_whitespace_check: false
+tab_check: false
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..775cc5a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+# libchrome
+
+## Overview
+This directory includes the source from Chrome's libbase for use in Chrome OS.
+
+See [libchrome.md](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/packages/libchrome.md)
+for more info.
diff --git a/base/android/java/src/org/chromium/base/BuildConfig.java b/base/android/java/src/org/chromium/base/BuildConfig.java
new file mode 100644
index 0000000..b8fa432
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BuildConfig.java
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * Build configuration. Generated on a per-target basis.
+ */
+public class BuildConfig {
+
+
+ public static final String FIREBASE_APP_ID = "";
+
+ public static final boolean DCHECK_IS_ON = false;
+
+ // The ID of the android string resource that stores the product version.
+ // This layer of indirection is necessary to make the resource dependency
+ // optional for android_apk targets/base_java (ex. for cronet).
+ public static final int R_STRING_PRODUCT_VERSION = 0;
+}
diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc
index fbab9d2..8a64093 100644
--- a/base/base_paths_posix.cc
+++ b/base/base_paths_posix.cc
@@ -19,7 +19,8 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
-#include "base/nix/xdg_util.h"
+// Unused, and this file is not ported to libchrome.
+// #include "base/nix/xdg_util.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/posix/sysctl.h"
@@ -76,6 +77,8 @@
return true;
#endif
}
+// Following paths are not supported in libchrome/libmojo.
+#if 0
case DIR_SRC_TEST_DATA_ROOT: {
FilePath path;
// On POSIX, unit tests execute two levels deep from the source root.
@@ -99,6 +102,7 @@
*result = cache_dir;
return true;
}
+#endif
}
return false;
}
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 52f00a9..166e58c 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -7,6 +7,11 @@
#include "build/build_config.h"
+#if defined(ANDROID)
+// Prefer Android's libbase definitions to our own.
+#include <android-base/macros.h>
+#endif // defined(ANDROID)
+
#if defined(COMPILER_MSVC) && !defined(__clang__)
#error "Only clang-cl is supported on Windows, see https://crbug.com/988071"
#endif
diff --git a/base/generated_build_date.h b/base/generated_build_date.h
new file mode 100644
index 0000000..8ed0af3
--- /dev/null
+++ b/base/generated_build_date.h
@@ -0,0 +1,3 @@
+#ifndef BUILD_DATE
+#define BUILD_DATE __DATE__ " " __TIME__ " PST"
+#endif // BUILD_DATE
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
index 12e10a4..2d93f07 100644
--- a/base/json/json_value_serializer_unittest.cc
+++ b/base/json/json_value_serializer_unittest.cc
@@ -393,7 +393,7 @@
ScopedTempDir temp_dir_;
};
-TEST_F(JSONFileValueSerializerTest, Roundtrip) {
+TEST_F(JSONFileValueSerializerTest, DISABLED_Roundtrip) {
FilePath original_file_path;
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
original_file_path = original_file_path.AppendASCII("serializer_test.json");
@@ -431,7 +431,7 @@
EXPECT_TRUE(DeleteFile(written_file_path));
}
-TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
+TEST_F(JSONFileValueSerializerTest, DISABLED_RoundtripNested) {
FilePath original_file_path;
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
original_file_path =
@@ -457,7 +457,7 @@
EXPECT_TRUE(DeleteFile(written_file_path));
}
-TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
+TEST_F(JSONFileValueSerializerTest, DISABLED_NoWhitespace) {
FilePath source_file_path;
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path));
source_file_path =
diff --git a/base/location.cc b/base/location.cc
index 917460f..674fafc 100644
--- a/base/location.cc
+++ b/base/location.cc
@@ -22,6 +22,7 @@
namespace {
+#if 0
// Returns the length of the given null terminated c-string.
constexpr size_t StrLen(const char* str) {
size_t str_len = 0;
@@ -76,6 +77,12 @@
"The file name does not match the expected prefix format.");
#endif
+#else
+
+constexpr size_t kStrippedPrefixLength = 0;
+
+#endif
+
} // namespace
Location::Location() = default;
diff --git a/base/logging_buildflags.h b/base/logging_buildflags.h
new file mode 100644
index 0000000..eedae7b
--- /dev/null
+++ b/base/logging_buildflags.h
@@ -0,0 +1,13 @@
+// This buildflag header file will remain manually edited since value of NDEBUG
+// or DCHECK_ALWAYS_ON cannot be passed from BUILD.gn using buildflag_header.
+
+#ifndef BASE_LOGGING_BUILDFLAGS_H_
+#define BASE_LOGGING_BUILDFLAGS_H_
+#include "build/buildflag.h"
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define BUILDFLAG_INTERNAL_ENABLE_LOG_ERROR_NOT_REACHED() (1)
+#else
+#define BUILDFLAG_INTERNAL_ENABLE_LOG_ERROR_NOT_REACHED() (0)
+#endif
+#define BUILDFLAG_INTERNAL_USE_RUNTIME_VLOG() (1)
+#endif // BASE_LOGGING_BUILDFLAGS_H_
diff --git a/base/message_loop/message_pump_for_ui.h b/base/message_loop/message_pump_for_ui.h
index a30ba0b..788a2fb 100644
--- a/base/message_loop/message_pump_for_ui.h
+++ b/base/message_loop/message_pump_for_ui.h
@@ -18,7 +18,7 @@
#include "base/message_loop/message_pump.h"
#elif BUILDFLAG(IS_NACL) || BUILDFLAG(IS_AIX)
// No MessagePumpForUI, see below.
-#elif defined(USE_GLIB)
+#elif defined(USE_GLIB) && !defined(ANDROID)
#include "base/message_loop/message_pump_glib.h"
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_BSD)
#include "base/message_loop/message_pump_libevent.h"
@@ -41,7 +41,7 @@
#elif BUILDFLAG(IS_NACL) || BUILDFLAG(IS_AIX)
// Currently NaCl and AIX don't have a MessagePumpForUI.
// TODO(abarth): Figure out if we need this.
-#elif defined(USE_GLIB)
+#elif defined(USE_GLIB) && !defined(ANDROID)
using MessagePumpForUI = MessagePumpGlib;
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_BSD)
using MessagePumpForUI = MessagePumpLibevent;
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
index c551d08..beb150b 100644
--- a/base/process/process_metrics_unittest.cc
+++ b/base/process/process_metrics_unittest.cc
@@ -952,6 +952,8 @@
} // namespace
+// ARC note: don't compile as SpawnMultiProcessTestChild brings in a lot of
+// extra dependency.
TEST(ProcessMetricsTest, GetChildOpenFdCount) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
index 9b03835..1f8c007 100644
--- a/base/strings/string_number_conversions_unittest.cc
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -874,7 +874,8 @@
StringPrintf("case %" PRIuS " \"%s\"", i, cases[i].input.c_str()));
double output;
errno = 1;
- EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
+ EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output))
+ << "for input=" << cases[i].input << "got output=" << output;
if (cases[i].success)
EXPECT_EQ(1, errno) << i; // confirm that errno is unchanged.
EXPECT_DOUBLE_EQ(cases[i].output, output);
diff --git a/base/task/common/task_annotator.h b/base/task/common/task_annotator.h
index 6fbb639..e9cc25e 100644
--- a/base/task/common/task_annotator.h
+++ b/base/task/common/task_annotator.h
@@ -28,6 +28,7 @@
public:
class ObserverForTesting {
public:
+ virtual ~ObserverForTesting() = default;
// Invoked just before RunTask() in the scope in which the task is about to
// be executed.
virtual void BeforeRunTask(const PendingTask* pending_task) = 0;
diff --git a/base/task/current_thread.h b/base/task/current_thread.h
index 6e21e72..69844f7 100644
--- a/base/task/current_thread.h
+++ b/base/task/current_thread.h
@@ -234,7 +234,7 @@
raw_ptr<sequence_manager::internal::SequenceManagerImpl> current_;
};
-#if !BUILDFLAG(IS_NACL)
+#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
// UI extension of CurrentThread.
class BASE_EXPORT CurrentUIThread : public CurrentThread {
@@ -289,7 +289,7 @@
MessagePumpForUI* GetMessagePumpForUI() const;
};
-#endif // !BUILDFLAG(IS_NACL)
+#endif // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
// ForIO extension of CurrentThread.
class BASE_EXPORT CurrentIOThread : public CurrentThread {
diff --git a/base/test/multiprocess_test.cc b/base/test/multiprocess_test.cc
index 209b645..d01fd11 100644
--- a/base/test/multiprocess_test.cc
+++ b/base/test/multiprocess_test.cc
@@ -52,6 +52,8 @@
MultiProcessTest::MultiProcessTest() = default;
+// Don't compile on ARC.
+#if 0
Process MultiProcessTest::SpawnChild(const std::string& procname) {
LaunchOptions options;
#if BUILDFLAG(IS_WIN)
@@ -64,6 +66,7 @@
const LaunchOptions& options) {
return SpawnMultiProcessTestChild(procname, MakeCmdLine(procname), options);
}
+#endif
CommandLine MultiProcessTest::MakeCmdLine(const std::string& procname) {
CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
diff --git a/base/test/test_pending_task.cc b/base/test/test_pending_task.cc
index 1b8d683..a20eec2 100644
--- a/base/test/test_pending_task.cc
+++ b/base/test/test_pending_task.cc
@@ -40,6 +40,8 @@
TestPendingTask::~TestPendingTask() = default;
+// Unsupported in libchrome.
+#if 0
void TestPendingTask::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
state->SetString("posting_function", location.ToString());
@@ -63,10 +65,14 @@
AsValueInto(state.get());
return std::move(state);
}
+#endif
std::string TestPendingTask::ToString() const {
std::string output("TestPendingTask(");
+// Unsupported in libchrome.
+#if 0
AsValue()->AppendAsTraceFormat(&output);
+#endif
output += ")";
return output;
}
diff --git a/base/test/test_pending_task.h b/base/test/test_pending_task.h
index 5ceb674..7b5ed6a 100644
--- a/base/test/test_pending_task.h
+++ b/base/test/test_pending_task.h
@@ -67,10 +67,13 @@
TimeDelta delay;
TestNestability nestability;
+// Unsupported in libchrome.
+#if 0
// Functions for using test pending task with tracing, useful in unit
// testing.
void AsValueInto(base::trace_event::TracedValue* state) const;
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+#endif
std::string ToString() const;
};
diff --git a/base/third_party/double_conversion/double-conversion/double-conversion.h b/base/third_party/double_conversion/double-conversion/double-conversion.h
new file mode 100644
index 0000000..1552f0b
--- /dev/null
+++ b/base/third_party/double_conversion/double-conversion/double-conversion.h
@@ -0,0 +1 @@
+#include <double-conversion/double-conversion.h>
diff --git a/base/third_party/libevent/event.h b/base/third_party/libevent/event.h
new file mode 100644
index 0000000..d47d797
--- /dev/null
+++ b/base/third_party/libevent/event.h
@@ -0,0 +1,10 @@
+// The Chromium build contains its own checkout of libevent. This stub is used
+// when building the Chrome OS or Android libchrome package to instead use the
+// system headers.
+#if defined(__ANDROID__) || defined(__ANDROID_HOST__)
+#include <event2/event.h>
+#include <event2/event_compat.h>
+#include <event2/event_struct.h>
+#else
+#include <event.h>
+#endif
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
new file mode 100644
index 0000000..59beafb
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#error "symbolize support was removed from libchrome"
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
index ba1ea6f..d0f9ed3 100644
--- a/base/threading/thread_id_name_manager.cc
+++ b/base/threading/thread_id_name_manager.cc
@@ -99,7 +99,7 @@
// cause a deadlock when the first allocation happens in the
// ThreadIdNameManager itself when holding the lock.
trace_event::AllocationContextTracker::SetCurrentThreadName(
- leaked_str->c_str());
+ leaked_str->c_str());
}
const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index c33ef6b..8ed3154 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -89,6 +89,13 @@
// GetTLSValue() to retrieve the value of slot as it has already been reset
// in Posix.
static void OnThreadExit(void* value);
+ // Normally, Chrome runs as a process, so freeing the TLS is not needed since
+ // the OS will perform that while it's reclaiming the process' memory upon
+ // termination. If, however, this code is used inside a library that is
+ // dynamically loaded and unloaded, the consumer is responsible for calling
+ // this after all Chrome threads have stopped and prior to unloading the
+ // library.
+ static void ForceFreeTLS();
#endif
};
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 5b1473e..d54f0dd 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -22,8 +22,16 @@
import textwrap
import zipfile
+# pylib conflicts with mojo/public/tools/bindings/pylib. Prioritize
+# build/android/pylib.
+# PYTHONPATH wouldn't help in this case, because soong put source files under
+# temp directory for each build, so the abspath is unknown until the
+# execution.
sys.path.append(os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, os.pardir))
+# For soong build
+sys.path.insert(0, os.path.join(os.path.dirname(__file__),
+ os.pardir, os.pardir))
import gn_helpers
# Use relative paths to improved hermetic property of build scripts.
diff --git a/build/build_config.h b/build/build_config.h
index ac021d1..99b63c9 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -66,7 +66,7 @@
// __native_client__ must be first, so that other OS_ defines are not set.
#define OS_NACL 1
#elif defined(ANDROID)
-#define OS_ANDROID 1
+#define OS_ANDROID
#elif defined(__APPLE__)
// Only include TargetConditionals after testing ANDROID as some Android builds
// on the Mac have this header available and it's not needed unless the target
diff --git a/build/buildflag_header.gni b/build/buildflag_header.gni
index f7b42f7..e414086 100644
--- a/build/buildflag_header.gni
+++ b/build/buildflag_header.gni
@@ -93,9 +93,10 @@
# "SPAM_SERVER_URL=\"http://www.example.com/\"",
# ]
# }
+
template("buildflag_header") {
action(target_name) {
- script = "//build/write_buildflag_header.py"
+ script = "build/write_buildflag_header.py"
if (defined(invoker.header_dir)) {
header_file = "${invoker.header_dir}/${invoker.header}"
@@ -132,6 +133,6 @@
"visibility",
])
- public_deps = [ "//build:buildflag_header_h" ]
+ public_deps = [ ":buildflag_header_h" ]
}
}
diff --git a/crypto/crypto_export.h b/crypto/crypto_export.h
new file mode 100644
index 0000000..66bd53c
--- /dev/null
+++ b/crypto/crypto_export.h
@@ -0,0 +1,32 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_CRYPTO_EXPORT_H_
+#define CRYPTO_CRYPTO_EXPORT_H_
+
+// Defines CRYPTO_EXPORT so that functionality implemented by the crypto module
+// can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CRYPTO_IMPLEMENTATION)
+#define CRYPTO_EXPORT __declspec(dllexport)
+#else
+#define CRYPTO_EXPORT __declspec(dllimport)
+#endif // defined(CRYPTO_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(CRYPTO_IMPLEMENTATION)
+#define CRYPTO_EXPORT __attribute__((visibility("default")))
+#else
+#define CRYPTO_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define CRYPTO_EXPORT
+#endif
+
+#endif // CRYPTO_CRYPTO_EXPORT_H_
diff --git a/crypto/crypto_unittests.isolate b/crypto/crypto_unittests.isolate
new file mode 100644
index 0000000..3c7e42a
--- /dev/null
+++ b/crypto/crypto_unittests.isolate
@@ -0,0 +1,42 @@
+# Copyright 2015 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'variables': {
+ 'command': [
+ '../testing/test_env.py',
+ '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ },
+ 'conditions': [
+ ['OS=="linux" or OS=="mac" or OS=="win"', {
+ 'variables': {
+ 'files': [
+ '../testing/test_env.py',
+ ],
+ },
+ }],
+ ['OS=="mac" and asan==1 and fastbuild==0', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/crypto_unittests.dSYM/',
+ ],
+ },
+ }],
+ ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/crypto_unittests.exe.pdb',
+ ],
+ },
+ }],
+ ],
+ 'includes': [
+ '../base/base.isolate',
+ ],
+}
diff --git a/crypto/hmac.cc b/crypto/hmac.cc
new file mode 100644
index 0000000..e471130
--- /dev/null
+++ b/crypto/hmac.cc
@@ -0,0 +1,61 @@
+// Copyright 2012 The Chromium Authors
+// 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 <stddef.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "crypto/secure_util.h"
+#include "crypto/symmetric_key.h"
+
+namespace crypto {
+
+bool HMAC::Init(SymmetricKey* key) {
+ std::string raw_key;
+ bool result = key->GetRawKey(&raw_key) && Init(raw_key);
+ // Zero out key copy. This might get optimized away, but one can hope.
+ // Using std::string to store key info at all is a larger problem.
+ std::fill(raw_key.begin(), raw_key.end(), 0);
+ return result;
+}
+
+size_t HMAC::DigestLength() const {
+ switch (hash_alg_) {
+ case SHA1:
+ return 20;
+ case SHA256:
+ return 32;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+bool HMAC::Verify(const base::StringPiece& data,
+ const base::StringPiece& digest) const {
+ if (digest.size() != DigestLength())
+ return false;
+ return VerifyTruncated(data, digest);
+}
+
+bool HMAC::VerifyTruncated(const base::StringPiece& data,
+ const base::StringPiece& digest) const {
+ if (digest.empty())
+ return false;
+ size_t digest_length = DigestLength();
+ std::unique_ptr<unsigned char[]> computed_digest(
+ new unsigned char[digest_length]);
+ if (!Sign(data, computed_digest.get(), digest_length))
+ return false;
+
+ return SecureMemEqual(digest.data(), computed_digest.get(),
+ std::min(digest.size(), digest_length));
+}
+
+} // namespace crypto
diff --git a/crypto/hmac.h b/crypto/hmac.h
new file mode 100644
index 0000000..10bb641
--- /dev/null
+++ b/crypto/hmac.h
@@ -0,0 +1,96 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Utility class for calculating the HMAC for a given message. We currently
+// only support SHA1 for the hash algorithm, but this can be extended easily.
+
+#ifndef CRYPTO_HMAC_H_
+#define CRYPTO_HMAC_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/strings/string_piece.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Simplify the interface and reduce includes by abstracting out the internals.
+struct HMACPlatformData;
+class SymmetricKey;
+
+class CRYPTO_EXPORT HMAC {
+ public:
+ // The set of supported hash functions. Extend as required.
+ enum HashAlgorithm {
+ SHA1,
+ SHA256,
+ };
+
+ explicit HMAC(HashAlgorithm hash_alg);
+
+ HMAC(const HMAC&) = delete;
+ HMAC& operator=(const HMAC&) = delete;
+
+ ~HMAC();
+
+ // Returns the length of digest that this HMAC will create.
+ size_t DigestLength() const;
+
+ // TODO(abarth): Add a PreferredKeyLength() member function.
+
+ // Initializes this instance using |key| of the length |key_length|. Call Init
+ // only once. It returns false on the second or later calls.
+ //
+ // NOTE: the US Federal crypto standard FIPS 198, Section 3 says:
+ // The size of the key, K, shall be equal to or greater than L/2, where L
+ // is the size of the hash function output.
+ // In FIPS 198-1 (and SP-800-107, which describes key size recommendations),
+ // this requirement is gone. But a system crypto library may still enforce
+ // this old requirement. If the key is shorter than this recommended value,
+ // Init() may fail.
+ [[nodiscard]] bool Init(const unsigned char* key, size_t key_length);
+
+ // Initializes this instance using |key|. Call Init
+ // only once. It returns false on the second or later calls.
+ [[nodiscard]] bool Init(SymmetricKey* key);
+
+ // Initializes this instance using |key|. Call Init only once. It returns
+ // false on the second or later calls.
+ [[nodiscard]] bool Init(const base::StringPiece& key) {
+ return Init(reinterpret_cast<const unsigned char*>(key.data()),
+ key.size());
+ }
+
+ // Calculates the HMAC for the message in |data| using the algorithm supplied
+ // to the constructor and the key supplied to the Init method. The HMAC is
+ // returned in |digest|, which has |digest_length| bytes of storage available.
+ [[nodiscard]] bool Sign(const base::StringPiece& data, unsigned char* digest,
+ size_t digest_length) const;
+
+ // Verifies that the HMAC for the message in |data| equals the HMAC provided
+ // in |digest|, using the algorithm supplied to the constructor and the key
+ // supplied to the Init method. Use of this method is strongly recommended
+ // over using Sign() with a manual comparison (such as memcmp), as such
+ // comparisons may result in side-channel disclosures, such as timing, that
+ // undermine the cryptographic integrity. |digest| must be exactly
+ // |DigestLength()| bytes long.
+ [[nodiscard]] bool Verify(const base::StringPiece& data,
+ const base::StringPiece& digest) const;
+
+ // Verifies a truncated HMAC, behaving identical to Verify(), except
+ // that |digest| is allowed to be smaller than |DigestLength()|.
+ [[nodiscard]] bool VerifyTruncated(
+ const base::StringPiece& data,
+ const base::StringPiece& digest) const;
+
+ private:
+ HashAlgorithm hash_alg_;
+ std::unique_ptr<HMACPlatformData> plat_;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_HMAC_H_
diff --git a/crypto/hmac_nss.cc b/crypto/hmac_nss.cc
new file mode 100644
index 0000000..e06a480
--- /dev/null
+++ b/crypto/hmac_nss.cc
@@ -0,0 +1,119 @@
+// Copyright 2011 The Chromium Authors
+// 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/hmac_unittest.cc b/crypto/hmac_unittest.cc
new file mode 100644
index 0000000..9cd3147
--- /dev/null
+++ b/crypto/hmac_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include <string>
+
+#include "crypto/hmac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+static const size_t kSHA1DigestSize = 20;
+static const size_t kSHA256DigestSize = 32;
+
+static const char* kSimpleKey =
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
+static const size_t kSimpleKeyLength = 80;
+
+static const struct {
+ const char *data;
+ const int data_len;
+ const char *digest;
+} kSimpleHmacCases[] = {
+ { "Test Using Larger Than Block-Size Key - Hash Key First", 54,
+ "\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55"
+ "\xED\x40\x21\x12" },
+ { "Test Using Larger Than Block-Size Key and Larger "
+ "Than One Block-Size Data", 73,
+ "\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08"
+ "\xBB\xFF\x1A\x91" }
+};
+
+TEST(HMACTest, HmacSafeBrowsingResponseTest) {
+ const int kKeySize = 16;
+
+ // Client key.
+ const unsigned char kClientKey[kKeySize] =
+ { 0xbf, 0xf6, 0x83, 0x4b, 0x3e, 0xa3, 0x23, 0xdd,
+ 0x96, 0x78, 0x70, 0x8e, 0xa1, 0x9d, 0x3b, 0x40 };
+
+ // Expected HMAC result using kMessage and kClientKey.
+ const unsigned char kReceivedHmac[kSHA1DigestSize] =
+ { 0xb9, 0x3c, 0xd6, 0xf0, 0x49, 0x47, 0xe2, 0x52,
+ 0x59, 0x7a, 0xbd, 0x1f, 0x2b, 0x4c, 0x83, 0xad,
+ 0x86, 0xd2, 0x48, 0x85 };
+
+ const char kMessage[] =
+"n:1896\ni:goog-malware-shavar\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shav"
+"ar_s_445-450\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_439-444\nu:s"
+".ytimg.com/safebrowsing/rd/goog-malware-shavar_s_437\nu:s.ytimg.com/safebrowsi"
+"ng/rd/goog-malware-shavar_s_436\nu:s.ytimg.com/safebrowsing/rd/goog-malware-sh"
+"avar_s_433-435\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_431\nu:s.y"
+"timg.com/safebrowsing/rd/goog-malware-shavar_s_430\nu:s.ytimg.com/safebrowsing"
+"/rd/goog-malware-shavar_s_429\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shav"
+"ar_s_428\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_426\nu:s.ytimg.c"
+"om/safebrowsing/rd/goog-malware-shavar_s_424\nu:s.ytimg.com/safebrowsing/rd/go"
+"og-malware-shavar_s_423\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_4"
+"22\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_420\nu:s.ytimg.com/saf"
+"ebrowsing/rd/goog-malware-shavar_s_419\nu:s.ytimg.com/safebrowsing/rd/goog-mal"
+"ware-shavar_s_414\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_409-411"
+"\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_405\nu:s.ytimg.com/safeb"
+"rowsing/rd/goog-malware-shavar_s_404\nu:s.ytimg.com/safebrowsing/rd/goog-malwa"
+"re-shavar_s_402\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_401\nu:s."
+"ytimg.com/safebrowsing/rd/goog-malware-shavar_a_973-978\nu:s.ytimg.com/safebro"
+"wsing/rd/goog-malware-shavar_a_937-972\nu:s.ytimg.com/safebrowsing/rd/goog-mal"
+"ware-shavar_a_931-936\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_a_925"
+"-930\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_a_919-924\ni:goog-phis"
+"h-shavar\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2633\nu:s.ytimg.co"
+"m/safebrowsing/rd/goog-phish-shavar_a_2632\nu:s.ytimg.com/safebrowsing/rd/goog"
+"-phish-shavar_a_2629-2631\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2"
+"626-2628\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2625\n";
+
+ std::string message_data(kMessage);
+
+ crypto::HMAC hmac(crypto::HMAC::SHA1);
+ ASSERT_TRUE(hmac.Init(kClientKey, kKeySize));
+ unsigned char calculated_hmac[kSHA1DigestSize];
+
+ EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize));
+ EXPECT_EQ(0, memcmp(kReceivedHmac, calculated_hmac, kSHA1DigestSize));
+}
+
+// Test cases from RFC 2202 section 3
+TEST(HMACTest, RFC2202TestCases) {
+ const struct {
+ const char *key;
+ const int key_len;
+ const char *data;
+ const int data_len;
+ const char *digest;
+ } cases[] = {
+ { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+ "\x0B\x0B\x0B\x0B", 20,
+ "Hi There", 8,
+ "\xB6\x17\x31\x86\x55\x05\x72\x64\xE2\x8B\xC0\xB6\xFB\x37\x8C\x8E"
+ "\xF1\x46\xBE\x00" },
+ { "Jefe", 4,
+ "what do ya want for nothing?", 28,
+ "\xEF\xFC\xDF\x6A\xE5\xEB\x2F\xA2\xD2\x74\x16\xD5\xF1\x84\xDF\x9C"
+ "\x25\x9A\x7C\x79" },
+ { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA", 20,
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD", 50,
+ "\x12\x5D\x73\x42\xB9\xAC\x11\xCD\x91\xA3\x9A\xF4\x8A\xA1\x7B\x4F"
+ "\x63\xF1\x75\xD3" },
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+ "\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD", 50,
+ "\x4C\x90\x07\xF4\x02\x62\x50\xC6\xBC\x84\x14\xF9\xBF\x50\xC8\x6C"
+ "\x2D\x72\x35\xDA" },
+ { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+ "\x0C\x0C\x0C\x0C", 20,
+ "Test With Truncation", 20,
+ "\x4C\x1A\x03\x42\x4B\x55\xE0\x7F\xE7\xF2\x7B\xE1\xD5\x8B\xB9\x32"
+ "\x4A\x9A\x5A\x04" },
+ { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ 80,
+ "Test Using Larger Than Block-Size Key - Hash Key First", 54,
+ "\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55"
+ "\xED\x40\x21\x12" },
+ { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ 80,
+ "Test Using Larger Than Block-Size Key and Larger "
+ "Than One Block-Size Data", 73,
+ "\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08"
+ "\xBB\xFF\x1A\x91" }
+ };
+
+ for (size_t i = 0; i < arraysize(cases); ++i) {
+ crypto::HMAC hmac(crypto::HMAC::SHA1);
+ ASSERT_TRUE(hmac.Init(reinterpret_cast<const unsigned char*>(cases[i].key),
+ cases[i].key_len));
+ std::string data_string(cases[i].data, cases[i].data_len);
+ unsigned char digest[kSHA1DigestSize];
+ EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize));
+ EXPECT_EQ(0, memcmp(cases[i].digest, digest, kSHA1DigestSize));
+ }
+}
+
+// TODO(wtc): add other test vectors from RFC 4231.
+TEST(HMACTest, RFC4231TestCase6) {
+ unsigned char key[131];
+ for (size_t i = 0; i < sizeof(key); ++i)
+ key[i] = 0xaa;
+
+ std::string data = "Test Using Larger Than Block-Size Key - Hash Key First";
+ ASSERT_EQ(54U, data.size());
+
+ static unsigned char kKnownHMACSHA256[] = {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+ };
+
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ ASSERT_TRUE(hmac.Init(key, sizeof(key)));
+ unsigned char calculated_hmac[kSHA256DigestSize];
+
+ EXPECT_EQ(kSHA256DigestSize, hmac.DigestLength());
+ EXPECT_TRUE(hmac.Sign(data, calculated_hmac, kSHA256DigestSize));
+ EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize));
+}
+
+// Based on NSS's FIPS HMAC power-up self-test.
+TEST(HMACTest, NSSFIPSPowerUpSelfTest) {
+ static const char kKnownMessage[] =
+ "The test message for the MD2, MD5, and SHA-1 hashing algorithms.";
+
+ static const unsigned char kKnownSecretKey[] = {
+ 0x46, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x54, 0x68, 0x75, 0x6e,
+ 0x64, 0x65, 0x72, 0x42, 0x69, 0x72, 0x64, 0x20,
+ 0x61, 0x72, 0x65, 0x20, 0x61, 0x77, 0x65, 0x73,
+ 0x6f, 0x6d, 0x65, 0x21, 0x00
+ };
+
+ static const size_t kKnownSecretKeySize = sizeof(kKnownSecretKey);
+
+ // HMAC-SHA-1 known answer (20 bytes).
+ static const unsigned char kKnownHMACSHA1[] = {
+ 0xd5, 0x85, 0xf6, 0x5b, 0x39, 0xfa, 0xb9, 0x05,
+ 0x3b, 0x57, 0x1d, 0x61, 0xe7, 0xb8, 0x84, 0x1e,
+ 0x5d, 0x0e, 0x1e, 0x11
+ };
+
+ // HMAC-SHA-256 known answer (32 bytes).
+ static const unsigned char kKnownHMACSHA256[] = {
+ 0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44,
+ 0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14, 0x22, 0xe0,
+ 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9,
+ 0xa7, 0x1b, 0x56, 0x7d, 0x1d, 0x29, 0x40, 0x48
+ };
+
+ std::string message_data(kKnownMessage);
+
+ crypto::HMAC hmac(crypto::HMAC::SHA1);
+ ASSERT_TRUE(hmac.Init(kKnownSecretKey, kKnownSecretKeySize));
+ unsigned char calculated_hmac[kSHA1DigestSize];
+
+ EXPECT_EQ(kSHA1DigestSize, hmac.DigestLength());
+ EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize));
+ EXPECT_EQ(0, memcmp(kKnownHMACSHA1, calculated_hmac, kSHA1DigestSize));
+ EXPECT_TRUE(hmac.Verify(
+ message_data,
+ base::StringPiece(reinterpret_cast<const char*>(kKnownHMACSHA1),
+ kSHA1DigestSize)));
+ EXPECT_TRUE(hmac.VerifyTruncated(
+ message_data,
+ base::StringPiece(reinterpret_cast<const char*>(kKnownHMACSHA1),
+ kSHA1DigestSize / 2)));
+
+ crypto::HMAC hmac2(crypto::HMAC::SHA256);
+ ASSERT_TRUE(hmac2.Init(kKnownSecretKey, kKnownSecretKeySize));
+ unsigned char calculated_hmac2[kSHA256DigestSize];
+
+ EXPECT_TRUE(hmac2.Sign(message_data, calculated_hmac2, kSHA256DigestSize));
+ EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac2, kSHA256DigestSize));
+}
+
+TEST(HMACTest, HMACObjectReuse) {
+ crypto::HMAC hmac(crypto::HMAC::SHA1);
+ ASSERT_TRUE(
+ hmac.Init(reinterpret_cast<const unsigned char*>(kSimpleKey),
+ kSimpleKeyLength));
+ for (size_t i = 0; i < arraysize(kSimpleHmacCases); ++i) {
+ std::string data_string(kSimpleHmacCases[i].data,
+ kSimpleHmacCases[i].data_len);
+ unsigned char digest[kSHA1DigestSize];
+ EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize));
+ EXPECT_EQ(0, memcmp(kSimpleHmacCases[i].digest, digest, kSHA1DigestSize));
+ }
+}
+
+TEST(HMACTest, Verify) {
+ crypto::HMAC hmac(crypto::HMAC::SHA1);
+ ASSERT_TRUE(
+ hmac.Init(reinterpret_cast<const unsigned char*>(kSimpleKey),
+ kSimpleKeyLength));
+ const char empty_digest[kSHA1DigestSize] = { 0 };
+ for (size_t i = 0; i < arraysize(kSimpleHmacCases); ++i) {
+ // Expected results
+ EXPECT_TRUE(hmac.Verify(
+ base::StringPiece(kSimpleHmacCases[i].data,
+ kSimpleHmacCases[i].data_len),
+ base::StringPiece(kSimpleHmacCases[i].digest,
+ kSHA1DigestSize)));
+ // Mismatched size
+ EXPECT_FALSE(hmac.Verify(
+ base::StringPiece(kSimpleHmacCases[i].data,
+ kSimpleHmacCases[i].data_len),
+ base::StringPiece(kSimpleHmacCases[i].data,
+ kSimpleHmacCases[i].data_len)));
+
+ // Expected size, mismatched data
+ EXPECT_FALSE(hmac.Verify(
+ base::StringPiece(kSimpleHmacCases[i].data,
+ kSimpleHmacCases[i].data_len),
+ base::StringPiece(empty_digest, kSHA1DigestSize)));
+ }
+}
+
+TEST(HMACTest, EmptyKey) {
+ // Test vector from https://en.wikipedia.org/wiki/HMAC
+ const char* kExpectedDigest =
+ "\xFB\xDB\x1D\x1B\x18\xAA\x6C\x08\x32\x4B\x7D\x64\xB7\x1F\xB7\x63"
+ "\x70\x69\x0E\x1D";
+ base::StringPiece data("");
+
+ crypto::HMAC hmac(crypto::HMAC::SHA1);
+ ASSERT_TRUE(hmac.Init(NULL, 0));
+
+ unsigned char digest[kSHA1DigestSize];
+ EXPECT_TRUE(hmac.Sign(data, digest, kSHA1DigestSize));
+ EXPECT_EQ(0, memcmp(kExpectedDigest, digest, kSHA1DigestSize));
+
+ EXPECT_TRUE(hmac.Verify(
+ data, base::StringPiece(kExpectedDigest, kSHA1DigestSize)));
+}
diff --git a/crypto/libcrypto-compat.c b/crypto/libcrypto-compat.c
new file mode 100644
index 0000000..ab6509a
--- /dev/null
+++ b/crypto/libcrypto-compat.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */
+#include "crypto/libcrypto-compat.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include <string.h>
+#include <openssl/engine.h>
+
+const unsigned char* ASN1_STRING_get0_data(const ASN1_STRING* x)
+{
+ return x->data;
+}
+
+void BIO_set_data(BIO* a, void* ptr)
+{
+ a->ptr = ptr;
+}
+
+void* BIO_get_data(BIO* a)
+{
+ return a->ptr;
+}
+
+void BIO_set_init(BIO* a, int init)
+{
+ a->init = init;
+}
+
+int BIO_get_init(BIO* a) {
+ return a->init;
+}
+
+void BIO_set_shutdown(BIO* a, int shut)
+{
+ a->shutdown = shut;
+}
+
+static void *OPENSSL_zalloc(size_t num)
+{
+ void *ret = OPENSSL_malloc(num);
+
+ if (ret != NULL)
+ memset(ret, 0, num);
+ return ret;
+}
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+ /* If the fields n and e in r are NULL, the corresponding input
+ * parameters MUST be non-NULL for n and e. d may be
+ * left NULL (in case only the public key is used).
+ */
+ if ((r->n == NULL && n == NULL)
+ || (r->e == NULL && e == NULL))
+ return 0;
+
+ if (n != NULL) {
+ BN_free(r->n);
+ r->n = n;
+ }
+ if (e != NULL) {
+ BN_free(r->e);
+ r->e = e;
+ }
+ if (d != NULL) {
+ BN_free(r->d);
+ r->d = d;
+ }
+
+ return 1;
+}
+
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
+{
+ /* If the fields p and q in r are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((r->p == NULL && p == NULL)
+ || (r->q == NULL && q == NULL))
+ return 0;
+
+ if (p != NULL) {
+ BN_free(r->p);
+ r->p = p;
+ }
+ if (q != NULL) {
+ BN_free(r->q);
+ r->q = q;
+ }
+
+ return 1;
+}
+
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
+{
+ /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((r->dmp1 == NULL && dmp1 == NULL)
+ || (r->dmq1 == NULL && dmq1 == NULL)
+ || (r->iqmp == NULL && iqmp == NULL))
+ return 0;
+
+ if (dmp1 != NULL) {
+ BN_free(r->dmp1);
+ r->dmp1 = dmp1;
+ }
+ if (dmq1 != NULL) {
+ BN_free(r->dmq1);
+ r->dmq1 = dmq1;
+ }
+ if (iqmp != NULL) {
+ BN_free(r->iqmp);
+ r->iqmp = iqmp;
+ }
+
+ return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+ const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ if (n != NULL)
+ *n = r->n;
+ if (e != NULL)
+ *e = r->e;
+ if (d != NULL)
+ *d = r->d;
+}
+
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+ if (p != NULL)
+ *p = r->p;
+ if (q != NULL)
+ *q = r->q;
+}
+
+void RSA_get0_crt_params(const RSA *r,
+ const BIGNUM **dmp1, const BIGNUM **dmq1,
+ const BIGNUM **iqmp)
+{
+ if (dmp1 != NULL)
+ *dmp1 = r->dmp1;
+ if (dmq1 != NULL)
+ *dmq1 = r->dmq1;
+ if (iqmp != NULL)
+ *iqmp = r->iqmp;
+}
+
+void DSA_get0_pqg(const DSA *d,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ if (p != NULL)
+ *p = d->p;
+ if (q != NULL)
+ *q = d->q;
+ if (g != NULL)
+ *g = d->g;
+}
+
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ /* If the fields p, q and g in d are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((d->p == NULL && p == NULL)
+ || (d->q == NULL && q == NULL)
+ || (d->g == NULL && g == NULL))
+ return 0;
+
+ if (p != NULL) {
+ BN_free(d->p);
+ d->p = p;
+ }
+ if (q != NULL) {
+ BN_free(d->q);
+ d->q = q;
+ }
+ if (g != NULL) {
+ BN_free(d->g);
+ d->g = g;
+ }
+
+ return 1;
+}
+
+void DSA_get0_key(const DSA *d,
+ const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key != NULL)
+ *pub_key = d->pub_key;
+ if (priv_key != NULL)
+ *priv_key = d->priv_key;
+}
+
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ /* If the field pub_key in d is NULL, the corresponding input
+ * parameters MUST be non-NULL. The priv_key field may
+ * be left NULL.
+ */
+ if (d->pub_key == NULL && pub_key == NULL)
+ return 0;
+
+ if (pub_key != NULL) {
+ BN_free(d->pub_key);
+ d->pub_key = pub_key;
+ }
+ if (priv_key != NULL) {
+ BN_free(d->priv_key);
+ d->priv_key = priv_key;
+ }
+
+ return 1;
+}
+
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+ if (pr != NULL)
+ *pr = sig->r;
+ if (ps != NULL)
+ *ps = sig->s;
+}
+
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ if (r == NULL || s == NULL)
+ return 0;
+ BN_clear_free(sig->r);
+ BN_clear_free(sig->s);
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+ if (pr != NULL)
+ *pr = sig->r;
+ if (ps != NULL)
+ *ps = sig->s;
+}
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ if (r == NULL || s == NULL)
+ return 0;
+ BN_clear_free(sig->r);
+ BN_clear_free(sig->s);
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+void DH_get0_pqg(const DH *dh,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ if (p != NULL)
+ *p = dh->p;
+ if (q != NULL)
+ *q = dh->q;
+ if (g != NULL)
+ *g = dh->g;
+}
+
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ /* If the fields p and g in d are NULL, the corresponding input
+ * parameters MUST be non-NULL. q may remain NULL.
+ */
+ if ((dh->p == NULL && p == NULL)
+ || (dh->g == NULL && g == NULL))
+ return 0;
+
+ if (p != NULL) {
+ BN_free(dh->p);
+ dh->p = p;
+ }
+ if (q != NULL) {
+ BN_free(dh->q);
+ dh->q = q;
+ }
+ if (g != NULL) {
+ BN_free(dh->g);
+ dh->g = g;
+ }
+
+ if (q != NULL) {
+ dh->length = BN_num_bits(q);
+ }
+
+ return 1;
+}
+
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key != NULL)
+ *pub_key = dh->pub_key;
+ if (priv_key != NULL)
+ *priv_key = dh->priv_key;
+}
+
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ /* If the field pub_key in dh is NULL, the corresponding input
+ * parameters MUST be non-NULL. The priv_key field may
+ * be left NULL.
+ */
+ if (dh->pub_key == NULL && pub_key == NULL)
+ return 0;
+
+ if (pub_key != NULL) {
+ BN_free(dh->pub_key);
+ dh->pub_key = pub_key;
+ }
+ if (priv_key != NULL) {
+ BN_free(dh->priv_key);
+ dh->priv_key = priv_key;
+ }
+
+ return 1;
+}
+
+int DH_set_length(DH *dh, long length)
+{
+ dh->length = length;
+ return 1;
+}
+
+const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
+{
+ return ctx->iv;
+}
+
+unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx)
+{
+ return ctx->iv;
+}
+
+EVP_MD_CTX *EVP_MD_CTX_new(void)
+{
+ return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
+}
+
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+ EVP_MD_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+}
+
+HMAC_CTX *HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx = OPENSSL_zalloc(sizeof(HMAC_CTX));
+ if (ctx) {
+ HMAC_CTX_init(ctx);
+ }
+ return ctx;
+}
+
+void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ HMAC_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+}
+
+
+RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth)
+{
+ RSA_METHOD *ret;
+
+ ret = OPENSSL_malloc(sizeof(RSA_METHOD));
+
+ if (ret != NULL) {
+ memcpy(ret, meth, sizeof(*meth));
+ ret->name = OPENSSL_strdup(meth->name);
+ if (ret->name == NULL) {
+ OPENSSL_free(ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+int RSA_meth_set1_name(RSA_METHOD *meth, const char *name)
+{
+ char *tmpname;
+
+ tmpname = OPENSSL_strdup(name);
+ if (tmpname == NULL) {
+ return 0;
+ }
+
+ OPENSSL_free((char *)meth->name);
+ meth->name = tmpname;
+
+ return 1;
+}
+
+int RSA_meth_set_priv_enc(RSA_METHOD *meth,
+ int (*priv_enc) (int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa,
+ int padding))
+{
+ meth->rsa_priv_enc = priv_enc;
+ return 1;
+}
+
+int RSA_meth_set_priv_dec(RSA_METHOD *meth,
+ int (*priv_dec) (int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa,
+ int padding))
+{
+ meth->rsa_priv_dec = priv_dec;
+ return 1;
+}
+
+int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
+{
+ meth->finish = finish;
+ return 1;
+}
+
+void RSA_meth_free(RSA_METHOD *meth)
+{
+ if (meth != NULL) {
+ OPENSSL_free((char *)meth->name);
+ OPENSSL_free(meth);
+ }
+}
+
+int RSA_bits(const RSA *r)
+{
+ return (BN_num_bits(r->n));
+}
+
+RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_RSA) {
+ return NULL;
+ }
+ return pkey->pkey.rsa;
+}
+
+#endif /* OPENSSL_VERSION_NUMBER */
diff --git a/crypto/libcrypto-compat.h b/crypto/libcrypto-compat.h
new file mode 100644
index 0000000..8e5f72c
--- /dev/null
+++ b/crypto/libcrypto-compat.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef LIBCRYPTO_COMPAT_H
+#define LIBCRYPTO_COMPAT_H
+
+#include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/rsa.h>
+
+#include "crypto/crypto_export.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+CRYPTO_EXPORT const unsigned char* ASN1_STRING_get0_data(const ASN1_STRING* x);
+
+CRYPTO_EXPORT void BIO_set_data(BIO* a, void* ptr);
+CRYPTO_EXPORT void* BIO_get_data(BIO* a);
+CRYPTO_EXPORT void BIO_set_init(BIO* a, int init);
+CRYPTO_EXPORT int BIO_get_init(BIO* a);
+CRYPTO_EXPORT void BIO_set_shutdown(BIO* a, int shut);
+
+CRYPTO_EXPORT int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+CRYPTO_EXPORT int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+CRYPTO_EXPORT int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+CRYPTO_EXPORT void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
+CRYPTO_EXPORT void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+CRYPTO_EXPORT void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
+
+CRYPTO_EXPORT void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+CRYPTO_EXPORT int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+CRYPTO_EXPORT void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key);
+CRYPTO_EXPORT int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
+
+CRYPTO_EXPORT void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+CRYPTO_EXPORT int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+CRYPTO_EXPORT void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+CRYPTO_EXPORT int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+CRYPTO_EXPORT void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+CRYPTO_EXPORT int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+CRYPTO_EXPORT void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key);
+CRYPTO_EXPORT int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
+CRYPTO_EXPORT int DH_set_length(DH *dh, long length);
+
+CRYPTO_EXPORT const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx);
+CRYPTO_EXPORT unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx);
+CRYPTO_EXPORT EVP_MD_CTX *EVP_MD_CTX_new(void);
+CRYPTO_EXPORT void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
+#define EVP_CIPHER_impl_ctx_size(e) (e)->ctx_size
+#define EVP_CIPHER_CTX_get_cipher_data(ctx) (ctx)->cipher_data
+
+CRYPTO_EXPORT HMAC_CTX *HMAC_CTX_new(void);
+CRYPTO_EXPORT void HMAC_CTX_free(HMAC_CTX *ctx);
+
+#define TLS_client_method() TLSv1_2_client_method()
+
+CRYPTO_EXPORT RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth);
+CRYPTO_EXPORT int RSA_meth_set1_name(RSA_METHOD *meth, const char *name);
+#define RSA_meth_get_finish(meth) (meth)->finish
+CRYPTO_EXPORT int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding));
+CRYPTO_EXPORT int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding));
+CRYPTO_EXPORT int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa));
+CRYPTO_EXPORT void RSA_meth_free(RSA_METHOD *meth);
+
+CRYPTO_EXPORT int RSA_bits(const RSA *r);
+
+CRYPTO_EXPORT RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /* OPENSSL_VERSION_NUMBER */
+
+#endif /* LIBCRYPTO_COMPAT_H */
diff --git a/crypto/nss_crypto_module_delegate.h b/crypto/nss_crypto_module_delegate.h
new file mode 100644
index 0000000..83dbbc7
--- /dev/null
+++ b/crypto/nss_crypto_module_delegate.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
+#define CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
+
+#include <string>
+
+#include "base/functional/callback_forward.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace crypto {
+
+// PK11_SetPasswordFunc is a global setting. An implementation of
+// CryptoModuleBlockingPasswordDelegate should be passed using wincx() as the
+// user data argument (|wincx|) to relevant NSS functions, which the global
+// password handler will call to do the actual work. This delegate should only
+// be used in NSS calls on worker threads due to the blocking nature.
+class CryptoModuleBlockingPasswordDelegate {
+ public:
+ virtual ~CryptoModuleBlockingPasswordDelegate() {}
+
+ // Return a value suitable for passing to the |wincx| argument of relevant NSS
+ // functions. This should be used instead of passing the object pointer
+ // directly to avoid accidentally casting a pointer to a subclass to void* and
+ // then casting back to a pointer of the base class
+ void* wincx() { return this; }
+
+ // Requests a password to unlock |slot_name|. The interface is synchronous
+ // because NSS cannot issue an asynchronous request. |retry| is true if this
+ // is a request for the retry and we previously returned the wrong password.
+ // The implementation should set |*cancelled| to true if the user cancelled
+ // instead of entering a password, otherwise it should return the password the
+ // user entered.
+ virtual std::string RequestPassword(const std::string& slot_name, bool retry,
+ bool* cancelled) = 0;
+
+};
+
+// Extends CryptoModuleBlockingPasswordDelegate with the ability to return a
+// slot in which to act. (Eg, which slot to store a generated key in.)
+class NSSCryptoModuleDelegate : public CryptoModuleBlockingPasswordDelegate {
+ public:
+ ~NSSCryptoModuleDelegate() override {}
+
+ // Get the slot to store the generated key.
+ virtual ScopedPK11Slot RequestSlot() = 0;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
diff --git a/crypto/nss_key_util.cc b/crypto/nss_key_util.cc
new file mode 100644
index 0000000..8c32dd8
--- /dev/null
+++ b/crypto/nss_key_util.cc
@@ -0,0 +1,165 @@
+// Copyright 2015 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/nss_key_util.h"
+
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "crypto/nss_util.h"
+
+#if defined(USE_NSS_CERTS)
+#include <secmod.h>
+#include "crypto/nss_util_internal.h"
+#endif
+
+namespace crypto {
+
+namespace {
+
+#if defined(USE_NSS_CERTS)
+
+struct PublicKeyInfoDeleter {
+ inline void operator()(CERTSubjectPublicKeyInfo* spki) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+};
+
+typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
+ ScopedPublicKeyInfo;
+
+// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing
+// the CKA_ID of that public key or nullptr on error.
+ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) {
+ // First, decode and save the public key.
+ SECItem key_der;
+ key_der.type = siBuffer;
+ key_der.data = const_cast<unsigned char*>(input.data());
+ key_der.len = input.size();
+
+ ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
+ if (!spki)
+ return nullptr;
+
+ ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
+ if (!result)
+ return nullptr;
+
+ // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are
+ // supported.
+ if (SECKEY_GetPublicKeyType(result.get()) != rsaKey)
+ return nullptr;
+
+ return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
+}
+
+#endif // defined(USE_NSS_CERTS)
+
+} // namespace
+
+bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
+ uint16_t num_bits,
+ bool permanent,
+ ScopedSECKEYPublicKey* public_key,
+ ScopedSECKEYPrivateKey* private_key) {
+ DCHECK(slot);
+
+ PK11RSAGenParams param;
+ param.keySizeInBits = num_bits;
+ param.pe = 65537L;
+ SECKEYPublicKey* public_key_raw = nullptr;
+ private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
+ ¶m, &public_key_raw, permanent,
+ permanent /* sensitive */, nullptr));
+ if (!*private_key)
+ return false;
+
+ public_key->reset(public_key_raw);
+ return true;
+}
+
+ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
+ PK11SlotInfo* slot,
+ const std::vector<uint8_t>& input,
+ bool permanent) {
+ DCHECK(slot);
+
+ ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ DCHECK(arena);
+
+ // Excess data is illegal, but NSS silently accepts it, so first ensure that
+ // |input| consists of a single ASN.1 element.
+ SECItem input_item;
+ input_item.data = const_cast<unsigned char*>(input.data());
+ input_item.len = input.size();
+ SECItem der_private_key_info;
+ SECStatus rv =
+ SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
+ SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
+ if (rv != SECSuccess)
+ return nullptr;
+
+ // Allow the private key to be used for key unwrapping, data decryption,
+ // and signature generation.
+ const unsigned int key_usage =
+ KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
+ SECKEYPrivateKey* key_raw = nullptr;
+ rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot, &der_private_key_info, nullptr, nullptr, permanent,
+ permanent /* sensitive */, key_usage, &key_raw, nullptr);
+ if (rv != SECSuccess)
+ return nullptr;
+ return ScopedSECKEYPrivateKey(key_raw);
+}
+
+#if defined(USE_NSS_CERTS)
+
+ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
+ const std::vector<uint8_t>& input) {
+ EnsureNSSInit();
+
+ ScopedSECItem cka_id(MakeIDFromSPKI(input));
+ if (!cka_id)
+ return nullptr;
+
+ // Search all slots in all modules for the key with the given ID.
+ AutoSECMODListReadLock auto_lock;
+ const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
+ for (const SECMODModuleList* item = head; item != nullptr;
+ item = item->next) {
+ int slot_count = item->module->loaded ? item->module->slotCount : 0;
+ for (int i = 0; i < slot_count; i++) {
+ // Look for the key in slot |i|.
+ ScopedSECKEYPrivateKey key(
+ PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
+ if (key)
+ return key;
+ }
+ }
+
+ // The key wasn't found in any module.
+ return nullptr;
+}
+
+ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
+ const std::vector<uint8_t>& input,
+ PK11SlotInfo* slot) {
+ DCHECK(slot);
+
+ ScopedSECItem cka_id(MakeIDFromSPKI(input));
+ if (!cka_id)
+ return nullptr;
+
+ return ScopedSECKEYPrivateKey(
+ PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
+}
+
+#endif // defined(USE_NSS_CERTS)
+
+} // namespace crypto
diff --git a/crypto/nss_key_util.h b/crypto/nss_key_util.h
new file mode 100644
index 0000000..9142609
--- /dev/null
+++ b/crypto/nss_key_util.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_NSS_KEY_UTIL_H_
+#define CRYPTO_NSS_KEY_UTIL_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+#include "crypto/scoped_nss_types.h"
+
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+
+namespace crypto {
+
+// Generates a new RSA keypair of size |num_bits| in |slot|. Returns true on
+// success and false on failure. If |permanent| is true, the resulting key is
+// permanent and is not exportable in plaintext form.
+CRYPTO_EXPORT bool GenerateRSAKeyPairNSS(
+ PK11SlotInfo* slot,
+ uint16_t num_bits,
+ bool permanent,
+ ScopedSECKEYPublicKey* out_public_key,
+ ScopedSECKEYPrivateKey* out_private_key);
+
+// Imports a private key from |input| into |slot|. |input| is interpreted as a
+// DER-encoded PrivateKeyInfo block from PKCS #8. Returns nullptr on error. If
+// |permanent| is true, the resulting key is permanent and is not exportable in
+// plaintext form.
+CRYPTO_EXPORT ScopedSECKEYPrivateKey
+ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo* slot,
+ const std::vector<uint8_t>& input,
+ bool permanent);
+
+#if defined(USE_NSS_CERTS)
+
+// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for
+// the private key half in the key database. Returns the private key on success
+// or nullptr on error.
+CRYPTO_EXPORT ScopedSECKEYPrivateKey
+FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t>& input);
+
+// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for
+// the private key half in the slot specified by |slot|. Returns the private key
+// on success or nullptr on error.
+CRYPTO_EXPORT ScopedSECKEYPrivateKey
+FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t>& input,
+ PK11SlotInfo* slot);
+
+#endif // defined(USE_NSS_CERTS)
+
+} // namespace crypto
+
+#endif // CRYPTO_NSS_KEY_UTIL_H_
diff --git a/crypto/nss_key_util_unittest.cc b/crypto/nss_key_util_unittest.cc
new file mode 100644
index 0000000..c507900
--- /dev/null
+++ b/crypto/nss_key_util_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright 2015 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/nss_key_util.h"
+
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+class NSSKeyUtilTest : public testing::Test {
+ public:
+ void SetUp() override {
+ EnsureNSSInit();
+
+ internal_slot_.reset(PK11_GetInternalSlot());
+ ASSERT_TRUE(internal_slot_);
+ }
+
+ PK11SlotInfo* internal_slot() { return internal_slot_.get(); }
+
+ private:
+ ScopedPK11Slot internal_slot_;
+};
+
+TEST_F(NSSKeyUtilTest, GenerateRSAKeyPairNSS) {
+ const int kKeySizeBits = 1024;
+
+ ScopedSECKEYPublicKey public_key;
+ ScopedSECKEYPrivateKey private_key;
+ ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), kKeySizeBits,
+ false /* not permanent */, &public_key,
+ &private_key));
+
+ EXPECT_EQ(rsaKey, SECKEY_GetPublicKeyType(public_key.get()));
+ EXPECT_EQ(rsaKey, SECKEY_GetPrivateKeyType(private_key.get()));
+ EXPECT_EQ((kKeySizeBits + 7) / 8,
+ PK11_GetPrivateModulusLen(private_key.get()));
+}
+
+#if defined(USE_NSS_CERTS)
+TEST_F(NSSKeyUtilTest, FindNSSKeyFromPublicKeyInfo) {
+ // Create an NSS keypair, which will put the keys in the user's NSSDB.
+ ScopedSECKEYPublicKey public_key;
+ ScopedSECKEYPrivateKey private_key;
+ ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512,
+ false /* not permanent */, &public_key,
+ &private_key));
+
+ ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
+ ASSERT_TRUE(item);
+ std::vector<uint8_t> public_key_der(item->data, item->data + item->len);
+
+ ScopedSECKEYPrivateKey private_key2 =
+ FindNSSKeyFromPublicKeyInfo(public_key_der);
+ ASSERT_TRUE(private_key2);
+ EXPECT_EQ(private_key->pkcs11ID, private_key2->pkcs11ID);
+}
+
+TEST_F(NSSKeyUtilTest, FailedFindNSSKeyFromPublicKeyInfo) {
+ // Create an NSS keypair, which will put the keys in the user's NSSDB.
+ ScopedSECKEYPublicKey public_key;
+ ScopedSECKEYPrivateKey private_key;
+ ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512,
+ false /* not permanent */, &public_key,
+ &private_key));
+
+ ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
+ ASSERT_TRUE(item);
+ std::vector<uint8_t> public_key_der(item->data, item->data + item->len);
+
+ // Remove the keys from the DB, and make sure we can't find them again.
+ PK11_DestroyTokenObject(private_key->pkcs11Slot, private_key->pkcs11ID);
+ PK11_DestroyTokenObject(public_key->pkcs11Slot, public_key->pkcs11ID);
+
+ EXPECT_FALSE(FindNSSKeyFromPublicKeyInfo(public_key_der));
+}
+#endif // defined(USE_NSS_CERTS)
+
+} // namespace crypto
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
new file mode 100644
index 0000000..d38036c
--- /dev/null
+++ b/crypto/nss_util.cc
@@ -0,0 +1,1033 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/nss_util.h"
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <plarena.h>
+#include <prerror.h>
+#include <prinit.h>
+#include <prtime.h>
+#include <secmod.h>
+
+#include <memory>
+#include <utility>
+
+#include "crypto/nss_util_internal.h"
+
+#if defined(OS_OPENBSD)
+#include <sys/mount.h>
+#include <sys/param.h>
+#endif
+
+#if defined(OS_CHROMEOS)
+#include <dlfcn.h>
+#endif
+
+#include <map>
+#include <vector>
+
+#include "base/functional/bind.h"
+#include "base/cpu.h"
+#include "base/debug/alias.h"
+#include "base/debug/stack_trace.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/native_library.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/task/single_thread_task_executor.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+#if !defined(OS_CHROMEOS)
+#include "base/base_paths.h"
+#include "base/path_service.h"
+#endif
+
+// USE_NSS_CERTS means NSS is used for certificates and platform integration.
+// This requires additional support to manage the platform certificate and key
+// stores.
+#if defined(USE_NSS_CERTS)
+#include "base/synchronization/lock.h"
+#include "crypto/nss_crypto_module_delegate.h"
+#endif // defined(USE_NSS_CERTS)
+
+namespace crypto {
+
+namespace {
+
+#if defined(OS_CHROMEOS)
+const char kUserNSSDatabaseName[] = "UserNSSDB";
+
+// Constants for loading the Chrome OS TPM-backed PKCS #11 library.
+const char kChapsModuleName[] = "Chaps";
+const char kChapsPath[] = "libchaps.so";
+
+// Fake certificate authority database used for testing.
+static const base::FilePath::CharType kReadOnlyCertDB[] =
+ FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
+#endif // defined(OS_CHROMEOS)
+
+std::string GetNSSErrorMessage() {
+ std::string result;
+ if (PR_GetErrorTextLength()) {
+ std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
+ PRInt32 copied = PR_GetErrorText(error_text.get());
+ result = std::string(error_text.get(), copied);
+ } else {
+ result = base::StringPrintf("NSS error code: %d", PR_GetError());
+ }
+ return result;
+}
+
+#if defined(USE_NSS_CERTS)
+#if !defined(OS_CHROMEOS)
+base::FilePath GetDefaultConfigDirectory() {
+ base::FilePath dir;
+ PathService::Get(base::DIR_HOME, &dir);
+ if (dir.empty()) {
+ LOG(ERROR) << "Failed to get home directory.";
+ return dir;
+ }
+ dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
+ if (!base::CreateDirectory(dir)) {
+ LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
+ dir.clear();
+ }
+ DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
+ return dir;
+}
+#endif // !defined(OS_CHROMEOS)
+
+// On non-Chrome OS platforms, return the default config directory. On Chrome OS
+// test images, return a read-only directory with fake root CA certs (which are
+// used by the local Google Accounts server mock we use when testing our login
+// code). On Chrome OS non-test images (where the read-only directory doesn't
+// exist), return an empty path.
+base::FilePath GetInitialConfigDirectory() {
+#if defined(OS_CHROMEOS)
+ base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
+ if (!base::PathExists(database_dir))
+ database_dir.clear();
+ return database_dir;
+#else
+ return GetDefaultConfigDirectory();
+#endif // defined(OS_CHROMEOS)
+}
+
+// This callback for NSS forwards all requests to a caller-specified
+// CryptoModuleBlockingPasswordDelegate object.
+char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
+ crypto::CryptoModuleBlockingPasswordDelegate* delegate =
+ reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
+ if (delegate) {
+ bool cancelled = false;
+ std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
+ retry != PR_FALSE,
+ &cancelled);
+ if (cancelled)
+ return NULL;
+ char* result = PORT_Strdup(password.c_str());
+ password.replace(0, password.size(), password.size(), 0);
+ return result;
+ }
+ DLOG(ERROR) << "PK11 password requested with NULL arg";
+ return NULL;
+}
+
+// NSS creates a local cache of the sqlite database if it detects that the
+// filesystem the database is on is much slower than the local disk. The
+// detection doesn't work with the latest versions of sqlite, such as 3.6.22
+// (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set
+// the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's
+// detection when database_dir is on NFS. See http://crbug.com/48585.
+//
+// TODO(wtc): port this function to other USE_NSS_CERTS platforms. It is
+// defined only for OS_LINUX and OS_OPENBSD simply because the statfs structure
+// is OS-specific.
+//
+// Because this function sets an environment variable it must be run before we
+// go multi-threaded.
+void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) {
+ bool db_on_nfs = false;
+#if defined(OS_LINUX)
+ base::FileSystemType fs_type = base::FILE_SYSTEM_UNKNOWN;
+ if (base::GetFileSystemType(database_dir, &fs_type))
+ db_on_nfs = (fs_type == base::FILE_SYSTEM_NFS);
+#elif defined(OS_OPENBSD)
+ struct statfs buf;
+ if (statfs(database_dir.value().c_str(), &buf) == 0)
+ db_on_nfs = (strcmp(buf.f_fstypename, MOUNT_NFS) == 0);
+#else
+ NOTIMPLEMENTED();
+#endif
+
+ if (db_on_nfs) {
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ static const char kUseCacheEnvVar[] = "NSS_SDB_USE_CACHE";
+ if (!env->HasVar(kUseCacheEnvVar))
+ env->SetVar(kUseCacheEnvVar, "yes");
+ }
+}
+
+#endif // defined(USE_NSS_CERTS)
+
+// A singleton to initialize/deinitialize NSPR.
+// Separate from the NSS singleton because we initialize NSPR on the UI thread.
+// Now that we're leaking the singleton, we could merge back with the NSS
+// singleton.
+class NSPRInitSingleton {
+ private:
+ friend struct base::LazyInstanceTraitsBase<NSPRInitSingleton>;
+
+ NSPRInitSingleton() {
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ }
+
+ // NOTE(willchan): We don't actually execute this code since we leak NSS to
+ // prevent non-joinable threads from using NSS after it's already been shut
+ // down.
+ ~NSPRInitSingleton() {
+ PL_ArenaFinish();
+ PRStatus prstatus = PR_Cleanup();
+ if (prstatus != PR_SUCCESS)
+ LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?";
+ }
+};
+
+base::LazyInstance<NSPRInitSingleton>::Leaky
+ g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
+
+// Force a crash with error info on NSS_NoDB_Init failure.
+void CrashOnNSSInitFailure() {
+ int nss_error = PR_GetError();
+ int os_error = PR_GetOSError();
+ base::debug::Alias(&nss_error);
+ base::debug::Alias(&os_error);
+ LOG(ERROR) << "Error initializing NSS without a persistent database: "
+ << GetNSSErrorMessage();
+ LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
+}
+
+#if defined(OS_CHROMEOS)
+class ChromeOSUserData {
+ public:
+ using SlotReadyCallback = base::OnceCallback<void(ScopedPK11Slot)>;
+ explicit ChromeOSUserData(ScopedPK11Slot public_slot)
+ : public_slot_(std::move(public_slot)) {}
+ ~ChromeOSUserData() {
+ if (public_slot_) {
+ SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
+ if (status != SECSuccess)
+ PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+ }
+ }
+
+ ScopedPK11Slot GetPublicSlot() {
+ return ScopedPK11Slot(
+ public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL);
+ }
+
+ ScopedPK11Slot GetPrivateSlot(SlotReadyCallback callback) {
+ if (private_slot_)
+ return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
+ if (!callback.is_null())
+ tpm_ready_callback_list_.push_back(std::move(callback));
+ return ScopedPK11Slot();
+ }
+
+ void SetPrivateSlot(ScopedPK11Slot private_slot) {
+ DCHECK(!private_slot_);
+ private_slot_ = std::move(private_slot);
+
+ SlotReadyCallbackList callback_list;
+ callback_list.swap(tpm_ready_callback_list_);
+ for (SlotReadyCallbackList::iterator i = callback_list.begin();
+ i != callback_list.end();
+ ++i) {
+ std::move(*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
+ }
+ }
+
+ bool private_slot_initialization_started() const {
+ return private_slot_initialization_started_;
+ }
+
+ void set_private_slot_initialization_started() {
+ private_slot_initialization_started_ = true;
+ }
+
+ private:
+ using SlotReadyCallbackList =
+ std::vector<base::OnceCallback<void(ScopedPK11Slot)>>;
+
+ ScopedPK11Slot public_slot_;
+ ScopedPK11Slot private_slot_;
+
+ bool private_slot_initialization_started_ = false;
+
+ SlotReadyCallbackList tpm_ready_callback_list_;
+};
+
+class ScopedChapsLoadFixup {
+ public:
+ ScopedChapsLoadFixup();
+ ~ScopedChapsLoadFixup();
+
+ private:
+#if defined(COMPONENT_BUILD)
+ void *chaps_handle_;
+#endif
+};
+
+#if defined(COMPONENT_BUILD)
+
+ScopedChapsLoadFixup::ScopedChapsLoadFixup() {
+ // HACK: libchaps links the system protobuf and there are symbol conflicts
+ // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround.
+ chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND);
+}
+
+ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {
+ // LoadModule() will have taken a 2nd reference.
+ if (chaps_handle_)
+ dlclose(chaps_handle_);
+}
+
+#else
+
+ScopedChapsLoadFixup::ScopedChapsLoadFixup() {}
+ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {}
+
+#endif // defined(COMPONENT_BUILD)
+#endif // defined(OS_CHROMEOS)
+
+class NSSInitSingleton {
+ public:
+#if defined(OS_CHROMEOS)
+ // Used with PostTaskAndReply to pass handles to worker thread and back.
+ struct TPMModuleAndSlot {
+ explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
+ : chaps_module(init_chaps_module) {}
+ SECMODModule* chaps_module;
+ crypto::ScopedPK11Slot tpm_slot;
+ };
+
+ ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
+ const base::FilePath& path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // NSS is allowed to do IO on the current thread since dispatching
+ // to a dedicated thread would still have the affect of blocking
+ // the current thread, due to NSS's internal locking requirements
+ ScopedAllowBlockingForNSS allow_blocking;
+
+ base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
+ if (!base::CreateDirectory(nssdb_path)) {
+ LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
+ return ScopedPK11Slot();
+ }
+ return OpenSoftwareNSSDB(nssdb_path, db_name);
+ }
+
+ void EnableTPMTokenForNSS() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // If this gets set, then we'll use the TPM for certs with
+ // private keys, otherwise we'll fall back to the software
+ // implementation.
+ tpm_token_enabled_for_nss_ = true;
+ }
+
+ bool IsTPMTokenEnabledForNSS() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return tpm_token_enabled_for_nss_;
+ }
+
+ void InitializeTPMTokenAndSystemSlot(
+ int system_slot_id,
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Should not be called while there is already an initialization in
+ // progress.
+ DCHECK(!initializing_tpm_token_);
+ // If EnableTPMTokenForNSS hasn't been called, return false.
+ if (!tpm_token_enabled_for_nss_) {
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), false));
+ return;
+ }
+
+ // If everything is already initialized, then return true.
+ // Note that only |tpm_slot_| is checked, since |chaps_module_| could be
+ // NULL in tests while |tpm_slot_| has been set to the test DB.
+ if (tpm_slot_) {
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), true));
+ return;
+ }
+
+ // Note that a reference is not taken to chaps_module_. This is safe since
+ // NSSInitSingleton is Leaky, so the reference it holds is never released.
+ std::unique_ptr<TPMModuleAndSlot> tpm_args(
+ new TPMModuleAndSlot(chaps_module_));
+ TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+ base::BindOnce(&NSSInitSingleton::InitializeTPMTokenInThreadPool,
+ system_slot_id, tpm_args_ptr),
+ base::BindOnce(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
+ base::Unretained(this), // NSSInitSingleton is leaky
+ std::move(callback), std::move(tpm_args)));
+ initializing_tpm_token_ = true;
+ }
+
+ static void InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,
+ TPMModuleAndSlot* tpm_args) {
+ // NSS functions may reenter //net via extension hooks. If the reentered
+ // code needs to synchronously wait for a task to run but the thread pool in
+ // which that task must run doesn't have enough threads to schedule it, a
+ // deadlock occurs. To prevent that, the base::ScopedBlockingCall below
+ // increments the thread pool capacity for the duration of the TPM
+ // initialization.
+ base::ScopedBlockingCall scoped_blocking_call(
+ FROM_HERE, base::BlockingType::WILL_BLOCK);
+
+ if (!tpm_args->chaps_module) {
+ ScopedChapsLoadFixup chaps_loader;
+
+ DVLOG(3) << "Loading chaps...";
+ tpm_args->chaps_module = LoadModule(
+ kChapsModuleName,
+ kChapsPath,
+ // For more details on these parameters, see:
+ // https://developer.mozilla.org/en/PKCS11_Module_Specs
+ // slotFlags=[PublicCerts] -- Certificates and public keys can be
+ // read from this slot without requiring a call to C_Login.
+ // askpw=only -- Only authenticate to the token when necessary.
+ "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
+ }
+ if (tpm_args->chaps_module) {
+ tpm_args->tpm_slot =
+ GetTPMSlotForIdInThreadPool(tpm_args->chaps_module, token_slot_id);
+ }
+ }
+
+ void OnInitializedTPMTokenAndSystemSlot(
+ base::OnceCallback<void(bool)> callback,
+ std::unique_ptr<TPMModuleAndSlot> tpm_args) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
+ << ", got tpm slot: " << !!tpm_args->tpm_slot;
+
+ chaps_module_ = tpm_args->chaps_module;
+ tpm_slot_ = std::move(tpm_args->tpm_slot);
+ if (!chaps_module_ && test_system_slot_) {
+ // chromeos_unittests try to test the TPM initialization process. If we
+ // have a test DB open, pretend that it is the TPM slot.
+ tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
+ }
+ initializing_tpm_token_ = false;
+
+ if (tpm_slot_)
+ RunAndClearTPMReadyCallbackList();
+
+ std::move(callback).Run(!!tpm_slot_);
+ }
+
+ void RunAndClearTPMReadyCallbackList() {
+ TPMReadyCallbackList callback_list;
+ callback_list.swap(tpm_ready_callback_list_);
+ for (TPMReadyCallbackList::iterator i = callback_list.begin();
+ i != callback_list.end();
+ ++i) {
+ std::move(*i).Run();
+ }
+ }
+
+ bool IsTPMTokenReady(base::OnceClosure callback) {
+ if (!callback.is_null()) {
+ // Cannot DCHECK in the general case yet, but since the callback is
+ // a new addition to the API, DCHECK to make sure at least the new uses
+ // don't regress.
+ DCHECK(thread_checker_.CalledOnValidThread());
+ } else if (!thread_checker_.CalledOnValidThread()) {
+ // TODO(mattm): Change to DCHECK when callers have been fixed.
+ DVLOG(1) << "Called on wrong thread.\n"
+ << base::debug::StackTrace().ToString();
+ }
+
+ if (tpm_slot_)
+ return true;
+
+ if (!callback.is_null())
+ tpm_ready_callback_list_.push_back(std::move(callback));
+
+ return false;
+ }
+
+ // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
+ // id as an int. This should be safe since this is only used with chaps, which
+ // we also control.
+ static crypto::ScopedPK11Slot GetTPMSlotForIdInThreadPool(
+ SECMODModule* chaps_module,
+ CK_SLOT_ID slot_id) {
+ DCHECK(chaps_module);
+
+ DVLOG(3) << "Poking chaps module.";
+ SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
+ if (rv != SECSuccess)
+ PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
+
+ PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id);
+ if (!slot)
+ LOG(ERROR) << "TPM slot " << slot_id << " not found.";
+ return crypto::ScopedPK11Slot(slot);
+ }
+
+ bool InitializeNSSForChromeOSUser(const std::string& username_hash,
+ const base::FilePath& path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
+ // This user already exists in our mapping.
+ DVLOG(2) << username_hash << " already initialized.";
+ return false;
+ }
+
+ DVLOG(2) << "Opening NSS DB " << path.value();
+ std::string db_name = base::StringPrintf(
+ "%s %s", kUserNSSDatabaseName, username_hash.c_str());
+ ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
+ chromeos_user_map_[username_hash] =
+ std::make_unique<ChromeOSUserData>(std::move(public_slot));
+ return true;
+ }
+
+ bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+ return !chromeos_user_map_[username_hash]
+ ->private_slot_initialization_started();
+ }
+
+ void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+ chromeos_user_map_[username_hash]
+ ->set_private_slot_initialization_started();
+ }
+
+ void InitializeTPMForChromeOSUser(const std::string& username_hash,
+ CK_SLOT_ID slot_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+ DCHECK(chromeos_user_map_[username_hash]->
+ private_slot_initialization_started());
+
+ if (!chaps_module_)
+ return;
+
+ // Note that a reference is not taken to chaps_module_. This is safe since
+ // NSSInitSingleton is Leaky, so the reference it holds is never released.
+ std::unique_ptr<TPMModuleAndSlot> tpm_args(
+ new TPMModuleAndSlot(chaps_module_));
+ TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+ base::BindOnce(&NSSInitSingleton::InitializeTPMTokenInThreadPool,
+ slot_id, tpm_args_ptr),
+ base::BindOnce(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
+ base::Unretained(this), // NSSInitSingleton is leaky
+ username_hash, std::move(tpm_args)));
+ }
+
+ void OnInitializedTPMForChromeOSUser(
+ const std::string& username_hash,
+ std::unique_ptr<TPMModuleAndSlot> tpm_args) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(2) << "Got tpm slot for " << username_hash << " "
+ << !!tpm_args->tpm_slot;
+ chromeos_user_map_[username_hash]->SetPrivateSlot(
+ std::move(tpm_args->tpm_slot));
+ }
+
+ void InitializePrivateSoftwareSlotForChromeOSUser(
+ const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ VLOG(1) << "using software private slot for " << username_hash;
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+ DCHECK(chromeos_user_map_[username_hash]->
+ private_slot_initialization_started());
+
+ chromeos_user_map_[username_hash]->SetPrivateSlot(
+ chromeos_user_map_[username_hash]->GetPublicSlot());
+ }
+
+ ScopedPK11Slot GetPublicSlotForChromeOSUser(
+ const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (username_hash.empty()) {
+ DVLOG(2) << "empty username_hash";
+ return ScopedPK11Slot();
+ }
+
+ if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
+ LOG(ERROR) << username_hash << " not initialized.";
+ return ScopedPK11Slot();
+ }
+ return chromeos_user_map_[username_hash]->GetPublicSlot();
+ }
+
+ ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+ const std::string& username_hash,
+ base::OnceCallback<void(ScopedPK11Slot)> callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (username_hash.empty()) {
+ DVLOG(2) << "empty username_hash";
+ if (!callback.is_null()) {
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), ScopedPK11Slot()));
+ }
+ return ScopedPK11Slot();
+ }
+
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+ return chromeos_user_map_[username_hash]->GetPrivateSlot(
+ std::move(callback));
+ }
+
+ void CloseChromeOSUserForTesting(const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash);
+ DCHECK(i != chromeos_user_map_.end());
+ chromeos_user_map_.erase(i);
+ }
+
+ void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
+ // Ensure that a previous value of test_system_slot_ is not overwritten.
+ // Unsetting, i.e. setting a NULL, however is allowed.
+ DCHECK(!slot || !test_system_slot_);
+ test_system_slot_ = std::move(slot);
+ if (test_system_slot_) {
+ tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
+ RunAndClearTPMReadyCallbackList();
+ } else {
+ tpm_slot_.reset();
+ }
+ }
+#endif // defined(OS_CHROMEOS)
+
+#if !defined(OS_CHROMEOS)
+ PK11SlotInfo* GetPersistentNSSKeySlot() {
+ // TODO(mattm): Change to DCHECK when callers have been fixed.
+ if (!thread_checker_.CalledOnValidThread()) {
+ DVLOG(1) << "Called on wrong thread.\n"
+ << base::debug::StackTrace().ToString();
+ }
+
+ return PK11_GetInternalKeySlot();
+ }
+#endif
+
+#if defined(OS_CHROMEOS)
+ void GetSystemNSSKeySlotCallback(
+ base::OnceCallback<void(ScopedPK11Slot)> callback) {
+ std::move(callback).Run(
+ ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())));
+ }
+
+ ScopedPK11Slot GetSystemNSSKeySlot(
+ base::OnceCallback<void(ScopedPK11Slot)> callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // TODO(mattm): chromeos::TPMTokenloader always calls
+ // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is
+ // disabled, tpm_slot_ will be the first user's slot instead. Can that be
+ // detected and return NULL instead?
+
+ base::OnceClosure wrapped_callback;
+ if (!callback.is_null()) {
+ wrapped_callback = base::BindOnce(
+ &NSSInitSingleton::GetSystemNSSKeySlotCallback,
+ base::Unretained(this) /* singleton is leaky */, std::move(callback));
+ }
+ if (IsTPMTokenReady(std::move(wrapped_callback)))
+ return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()));
+ return ScopedPK11Slot();
+ }
+#endif
+
+#if defined(USE_NSS_CERTS)
+ base::Lock* write_lock() {
+ return &write_lock_;
+ }
+#endif // defined(USE_NSS_CERTS)
+
+ private:
+ friend struct base::LazyInstanceTraitsBase<NSSInitSingleton>;
+
+ NSSInitSingleton()
+ : tpm_token_enabled_for_nss_(false),
+ initializing_tpm_token_(false),
+ chaps_module_(NULL),
+ root_(NULL) {
+ // It's safe to construct on any thread, since LazyInstance will prevent any
+ // other threads from accessing until the constructor is done.
+ thread_checker_.DetachFromThread();
+
+ EnsureNSPRInit();
+
+ // We *must* have NSS >= 3.14.3.
+ static_assert(
+ (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) ||
+ (NSS_VMAJOR == 3 && NSS_VMINOR > 14) ||
+ (NSS_VMAJOR > 3),
+ "nss version check failed");
+ // Also check the run-time NSS version.
+ // NSS_VersionCheck is a >= check, not strict equality.
+ if (!NSS_VersionCheck("3.14.3")) {
+ LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is "
+ "required. Please upgrade to the latest NSS, and if you "
+ "still get this error, contact your distribution "
+ "maintainer.";
+ }
+
+ SECStatus status = SECFailure;
+ bool nodb_init = false;
+
+#if !defined(USE_NSS_CERTS)
+ // Use the system certificate store, so initialize NSS without database.
+ nodb_init = true;
+#endif
+
+ if (nodb_init) {
+ status = NSS_NoDB_Init(NULL);
+ if (status != SECSuccess) {
+ CrashOnNSSInitFailure();
+ return;
+ }
+#if defined(OS_IOS)
+ root_ = InitDefaultRootCerts();
+#endif // defined(OS_IOS)
+ } else {
+#if defined(USE_NSS_CERTS)
+ base::FilePath database_dir = GetInitialConfigDirectory();
+ if (!database_dir.empty()) {
+ // This duplicates the work which should have been done in
+ // EarlySetupForNSSInit. However, this function is idempotent so
+ // there's no harm done.
+ UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
+
+ // Initialize with a persistent database (likely, ~/.pki/nssdb).
+ // Use "sql:" which can be shared by multiple processes safely.
+ std::string nss_config_dir =
+ base::StringPrintf("sql:%s", database_dir.value().c_str());
+#if defined(OS_CHROMEOS)
+ status = NSS_Init(nss_config_dir.c_str());
+#else
+ status = NSS_InitReadWrite(nss_config_dir.c_str());
+#endif
+ if (status != SECSuccess) {
+ LOG(ERROR) << "Error initializing NSS with a persistent "
+ "database (" << nss_config_dir
+ << "): " << GetNSSErrorMessage();
+ }
+ }
+ if (status != SECSuccess) {
+ VLOG(1) << "Initializing NSS without a persistent database.";
+ status = NSS_NoDB_Init(NULL);
+ if (status != SECSuccess) {
+ CrashOnNSSInitFailure();
+ return;
+ }
+ }
+
+ PK11_SetPasswordFunc(PKCS11PasswordFunc);
+
+ // If we haven't initialized the password for the NSS databases,
+ // initialize an empty-string password so that we don't need to
+ // log in.
+ PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+ if (slot) {
+ // PK11_InitPin may write to the keyDB, but no other thread can use NSS
+ // yet, so we don't need to lock.
+ if (PK11_NeedUserInit(slot))
+ PK11_InitPin(slot, NULL, NULL);
+ PK11_FreeSlot(slot);
+ }
+
+ root_ = InitDefaultRootCerts();
+#endif // defined(USE_NSS_CERTS)
+ }
+
+ // Disable MD5 certificate signatures. (They are disabled by default in
+ // NSS 3.14.)
+ NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
+ NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
+ 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
+ }
+
+ // NOTE(willchan): We don't actually execute this code since we leak NSS to
+ // prevent non-joinable threads from using NSS after it's already been shut
+ // down.
+ ~NSSInitSingleton() {
+#if defined(OS_CHROMEOS)
+ chromeos_user_map_.clear();
+#endif
+ tpm_slot_.reset();
+ if (root_) {
+ SECMOD_UnloadUserModule(root_);
+ SECMOD_DestroyModule(root_);
+ root_ = NULL;
+ }
+ if (chaps_module_) {
+ SECMOD_UnloadUserModule(chaps_module_);
+ SECMOD_DestroyModule(chaps_module_);
+ chaps_module_ = NULL;
+ }
+
+ SECStatus status = NSS_Shutdown();
+ if (status != SECSuccess) {
+ // We VLOG(1) because this failure is relatively harmless (leaking, but
+ // we're shutting down anyway).
+ VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609";
+ }
+ }
+
+ // Load nss's built-in root certs.
+ SECMODModule* InitDefaultRootCerts() {
+ SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL);
+ if (root)
+ return root;
+
+ // Aw, snap. Can't find/load root cert shared library.
+ // This will make it hard to talk to anybody via https.
+ // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
+ return NULL;
+ }
+
+ // Load the given module for this NSS session.
+ static SECMODModule* LoadModule(const char* name,
+ const char* library_path,
+ const char* params) {
+ std::string modparams = base::StringPrintf(
+ "name=\"%s\" library=\"%s\" %s",
+ name, library_path, params ? params : "");
+
+ // Shouldn't need to const_cast here, but SECMOD doesn't properly
+ // declare input string arguments as const. Bug
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed
+ // on NSS codebase to address this.
+ SECMODModule* module = SECMOD_LoadUserModule(
+ const_cast<char*>(modparams.c_str()), NULL, PR_FALSE);
+ if (!module) {
+ LOG(ERROR) << "Error loading " << name << " module into NSS: "
+ << GetNSSErrorMessage();
+ return NULL;
+ }
+ if (!module->loaded) {
+ LOG(ERROR) << "After loading " << name << ", loaded==false: "
+ << GetNSSErrorMessage();
+ SECMOD_DestroyModule(module);
+ return NULL;
+ }
+ return module;
+ }
+
+ bool tpm_token_enabled_for_nss_;
+ bool initializing_tpm_token_;
+ typedef std::vector<base::OnceClosure> TPMReadyCallbackList;
+ TPMReadyCallbackList tpm_ready_callback_list_;
+ SECMODModule* chaps_module_;
+ crypto::ScopedPK11Slot tpm_slot_;
+ SECMODModule* root_;
+#if defined(OS_CHROMEOS)
+ typedef std::map<std::string, std::unique_ptr<ChromeOSUserData>> ChromeOSUserMap;
+ ChromeOSUserMap chromeos_user_map_;
+ ScopedPK11Slot test_system_slot_;
+#endif
+#if defined(USE_NSS_CERTS)
+ // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
+ // is fixed, we will no longer need the lock.
+ base::Lock write_lock_;
+#endif // defined(USE_NSS_CERTS)
+
+ base::ThreadChecker thread_checker_;
+};
+
+base::LazyInstance<NSSInitSingleton>::Leaky
+ g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
+} // namespace
+
+#if defined(USE_NSS_CERTS)
+ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
+ const std::string& description) {
+ const std::string modspec =
+ base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
+ path.value().c_str(),
+ description.c_str());
+ PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
+ if (db_slot) {
+ if (PK11_NeedUserInit(db_slot))
+ PK11_InitPin(db_slot, NULL, NULL);
+ } else {
+ LOG(ERROR) << "Error opening persistent database (" << modspec
+ << "): " << GetNSSErrorMessage();
+ }
+ return ScopedPK11Slot(db_slot);
+}
+
+void EarlySetupForNSSInit() {
+ base::FilePath database_dir = GetInitialConfigDirectory();
+ if (!database_dir.empty())
+ UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
+}
+#endif
+
+void EnsureNSPRInit() {
+ g_nspr_singleton.Get();
+}
+
+void EnsureNSSInit() {
+ // Initializing SSL causes us to do blocking IO.
+ // Temporarily allow it until we fix
+ // http://code.google.com/p/chromium/issues/detail?id=59847
+ ScopedAllowBlockingForNSS allow_blocking;
+ g_nss_singleton.Get();
+}
+
+bool CheckNSSVersion(const char* version) {
+ return !!NSS_VersionCheck(version);
+}
+
+#if defined(USE_NSS_CERTS)
+base::Lock* GetNSSWriteLock() {
+ return g_nss_singleton.Get().write_lock();
+}
+
+AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) {
+ // May be NULL if the lock is not needed in our version of NSS.
+ if (lock_)
+ lock_->Acquire();
+}
+
+AutoNSSWriteLock::~AutoNSSWriteLock() {
+ if (lock_) {
+ lock_->AssertAcquired();
+ lock_->Release();
+ }
+}
+
+AutoSECMODListReadLock::AutoSECMODListReadLock()
+ : lock_(SECMOD_GetDefaultModuleListLock()) {
+ SECMOD_GetReadLock(lock_);
+ }
+
+AutoSECMODListReadLock::~AutoSECMODListReadLock() {
+ SECMOD_ReleaseReadLock(lock_);
+}
+#endif // defined(USE_NSS_CERTS)
+
+#if defined(OS_CHROMEOS)
+ScopedPK11Slot GetSystemNSSKeySlot(
+ base::OnceCallback<void(ScopedPK11Slot)> callback) {
+ return g_nss_singleton.Get().GetSystemNSSKeySlot(std::move(callback));
+}
+
+void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
+ g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot));
+}
+
+void EnableTPMTokenForNSS() {
+ g_nss_singleton.Get().EnableTPMTokenForNSS();
+}
+
+bool IsTPMTokenEnabledForNSS() {
+ return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
+}
+
+bool IsTPMTokenReady(base::OnceClosure callback) {
+ return g_nss_singleton.Get().IsTPMTokenReady(std::move(callback));
+}
+
+void InitializeTPMTokenAndSystemSlot(
+ int token_slot_id, base::OnceCallback<void(bool)> callback) {
+ g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
+ std::move(callback));
+}
+
+bool InitializeNSSForChromeOSUser(const std::string& username_hash,
+ const base::FilePath& path) {
+ return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash,
+ path);
+}
+
+bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
+ return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser(
+ username_hash);
+}
+
+void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
+ g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash);
+}
+
+void InitializeTPMForChromeOSUser(
+ const std::string& username_hash,
+ CK_SLOT_ID slot_id) {
+ g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
+}
+
+void InitializePrivateSoftwareSlotForChromeOSUser(
+ const std::string& username_hash) {
+ g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
+ username_hash);
+}
+
+ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
+ return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
+}
+
+ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+ const std::string& username_hash,
+ base::OnceCallback<void(ScopedPK11Slot)> callback) {
+ return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(
+ username_hash, std::move(callback));
+}
+
+void CloseChromeOSUserForTesting(const std::string& username_hash) {
+ g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash);
+}
+#endif // defined(OS_CHROMEOS)
+
+base::Time PRTimeToBaseTime(PRTime prtime) {
+ return base::Time::FromInternalValue(
+ prtime + base::Time::UnixEpoch().ToInternalValue());
+}
+
+PRTime BaseTimeToPRTime(base::Time time) {
+ return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
+}
+
+#if !defined(OS_CHROMEOS)
+PK11SlotInfo* GetPersistentNSSKeySlot() {
+ return g_nss_singleton.Get().GetPersistentNSSKeySlot();
+}
+#endif
+
+} // namespace crypto
diff --git a/crypto/nss_util.h b/crypto/nss_util.h
new file mode 100644
index 0000000..c2b5f36
--- /dev/null
+++ b/crypto/nss_util.h
@@ -0,0 +1,112 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_NSS_UTIL_H_
+#define CRYPTO_NSS_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+#include "base/functional/callback.h"
+#include "base/threading/thread_restrictions.h"
+#include "crypto/crypto_export.h"
+
+namespace base {
+class FilePath;
+class Lock;
+class Time;
+} // namespace base
+
+// This file specifically doesn't depend on any NSS or NSPR headers because it
+// is included by various (non-crypto) parts of chrome to call the
+// initialization functions.
+namespace crypto {
+
+class ScopedAllowBlockingForNSS : public base::ScopedAllowBlocking {};
+
+#if defined(USE_NSS_CERTS)
+// EarlySetupForNSSInit performs lightweight setup which must occur before the
+// process goes multithreaded. This does not initialise NSS. For test, see
+// EnsureNSSInit.
+CRYPTO_EXPORT void EarlySetupForNSSInit();
+#endif
+
+// Initialize NRPR if it isn't already initialized. This function is
+// thread-safe, and NSPR will only ever be initialized once.
+CRYPTO_EXPORT void EnsureNSPRInit();
+
+// Initialize NSS if it isn't already initialized. This must be called before
+// any other NSS functions. This function is thread-safe, and NSS will only
+// ever be initialized once.
+CRYPTO_EXPORT void EnsureNSSInit();
+
+// Check if the current NSS version is greater than or equals to |version|.
+// A sample version string is "3.12.3".
+bool CheckNSSVersion(const char* version);
+
+#if defined(OS_CHROMEOS)
+// Indicates that NSS should use the Chaps library so that we
+// can access the TPM through NSS. InitializeTPMTokenAndSystemSlot and
+// InitializeTPMForChromeOSUser must still be called to load the slots.
+CRYPTO_EXPORT void EnableTPMTokenForNSS();
+
+// Returns true if EnableTPMTokenForNSS has been called.
+CRYPTO_EXPORT bool IsTPMTokenEnabledForNSS();
+
+// Returns true if the TPM is owned and PKCS#11 initialized with the
+// user and security officer PINs, and has been enabled in NSS by
+// calling EnableTPMForNSS, and Chaps has been successfully
+// loaded into NSS.
+// If |callback| is non-null and the function returns false, the |callback| will
+// be run once the TPM is ready. |callback| will never be run if the function
+// returns true.
+[[nodiscard]] CRYPTO_EXPORT bool IsTPMTokenReady(base::OnceClosure callback)
+ ;
+
+// Initialize the TPM token and system slot. The |callback| will run on the same
+// thread with true if the token and slot were successfully loaded or were
+// already initialized. |callback| will be passed false if loading failed. Once
+// called, InitializeTPMTokenAndSystemSlot must not be called again until the
+// |callback| has been run.
+CRYPTO_EXPORT void InitializeTPMTokenAndSystemSlot(
+ int system_slot_id,
+ const base::OnceCallback<void(bool)>& callback);
+#endif
+
+// Convert a NSS PRTime value into a base::Time object.
+// We use a int64_t instead of PRTime here to avoid depending on NSPR headers.
+CRYPTO_EXPORT base::Time PRTimeToBaseTime(int64_t prtime);
+
+// Convert a base::Time object into a PRTime value.
+// We use a int64_t instead of PRTime here to avoid depending on NSPR headers.
+CRYPTO_EXPORT int64_t BaseTimeToPRTime(base::Time time);
+
+#if defined(USE_NSS_CERTS)
+// NSS has a bug which can cause a deadlock or stall in some cases when writing
+// to the certDB and keyDB. It also has a bug which causes concurrent key pair
+// generations to scribble over each other. To work around this, we synchronize
+// writes to the NSS databases with a global lock. The lock is hidden beneath a
+// function for easy disabling when the bug is fixed. Callers should allow for
+// it to return NULL in the future.
+//
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=564011
+base::Lock* GetNSSWriteLock();
+
+// A helper class that acquires the NSS write Lock while the AutoNSSWriteLock
+// is in scope.
+class CRYPTO_EXPORT AutoNSSWriteLock {
+ public:
+ AutoNSSWriteLock();
+ AutoNSSWriteLock(const AutoNSSWriteLock&) = delete;
+ AutoNSSWriteLock& operator=(const AutoNSSWriteLock&) = delete;
+
+ ~AutoNSSWriteLock();
+ private:
+ base::Lock *lock_;
+};
+#endif // defined(USE_NSS_CERTS)
+
+} // namespace crypto
+
+#endif // CRYPTO_NSS_UTIL_H_
diff --git a/crypto/nss_util_internal.h b/crypto/nss_util_internal.h
new file mode 100644
index 0000000..82dc060
--- /dev/null
+++ b/crypto/nss_util_internal.h
@@ -0,0 +1,113 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_NSS_UTIL_INTERNAL_H_
+#define CRYPTO_NSS_UTIL_INTERNAL_H_
+
+#include <secmodt.h>
+
+#include "base/functional/callback.h"
+#include "crypto/crypto_export.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace base {
+class FilePath;
+}
+
+// These functions return a type defined in an NSS header, and so cannot be
+// declared in nss_util.h. Hence, they are declared here.
+
+namespace crypto {
+
+// Opens an NSS software database in folder |path|, with the (potentially)
+// user-visible description |description|. Returns the slot for the opened
+// database, or NULL if the database could not be opened.
+CRYPTO_EXPORT ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
+ const std::string& description);
+
+#if !defined(OS_CHROMEOS)
+// Returns a reference to the default NSS key slot for storing persistent data.
+// Caller must release returned reference with PK11_FreeSlot.
+[[nodiscard]] CRYPTO_EXPORT PK11SlotInfo* GetPersistentNSSKeySlot();
+#endif
+
+// A helper class that acquires the SECMOD list read lock while the
+// AutoSECMODListReadLock is in scope.
+class CRYPTO_EXPORT AutoSECMODListReadLock {
+ public:
+ AutoSECMODListReadLock();
+ AutoSECMODListReadLock(const AutoSECMODListReadLock&) = delete;
+ AutoSECMODListReadLock& operator=(const AutoSECMODListReadLock&) = delete;
+
+ ~AutoSECMODListReadLock();
+
+ private:
+ SECMODListLock* lock_;
+};
+
+#if defined(OS_CHROMEOS)
+// Returns a reference to the system-wide TPM slot if it is loaded. If it is not
+// loaded and |callback| is non-null, the |callback| will be run once the slot
+// is loaded.
+[[nodiscard]] CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot(
+ base::OnceCallback<void(ScopedPK11Slot)> callback);
+
+// Sets the test system slot to |slot|, which means that |slot| will be exposed
+// through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will return true.
+// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
+// does not have to be called if the test system slot is set.
+// This must must not be called consecutively with a |slot| != NULL. If |slot|
+// is NULL, the test system slot is unset.
+CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
+
+// Prepare per-user NSS slot mapping. It is safe to call this function multiple
+// times. Returns true if the user was added, or false if it already existed.
+CRYPTO_EXPORT bool InitializeNSSForChromeOSUser(
+ const std::string& username_hash,
+ const base::FilePath& path);
+
+// Returns whether TPM for ChromeOS user still needs initialization. If
+// true is returned, the caller can proceed to initialize TPM slot for the
+// user, but should call |WillInitializeTPMForChromeOSUser| first.
+// |InitializeNSSForChromeOSUser| must have been called first.
+[[nodiscard]] CRYPTO_EXPORT bool ShouldInitializeTPMForChromeOSUser(
+ const std::string& username_hash);
+
+// Makes |ShouldInitializeTPMForChromeOSUser| start returning false.
+// Should be called before starting TPM initialization for the user.
+// Assumes |InitializeNSSForChromeOSUser| had already been called.
+CRYPTO_EXPORT void WillInitializeTPMForChromeOSUser(
+ const std::string& username_hash);
+
+// Use TPM slot |slot_id| for user. InitializeNSSForChromeOSUser must have been
+// called first.
+CRYPTO_EXPORT void InitializeTPMForChromeOSUser(
+ const std::string& username_hash,
+ CK_SLOT_ID slot_id);
+
+// Use the software slot as the private slot for user.
+// InitializeNSSForChromeOSUser must have been called first.
+CRYPTO_EXPORT void InitializePrivateSoftwareSlotForChromeOSUser(
+ const std::string& username_hash);
+
+// Returns a reference to the public slot for user.
+[[nodiscard]] CRYPTO_EXPORT ScopedPK11Slot GetPublicSlotForChromeOSUser(
+ const std::string& username_hash);
+
+// Returns the private slot for |username_hash| if it is loaded. If it is not
+// loaded and |callback| is non-null, the |callback| will be run once the slot
+// is loaded.
+[[nodiscard]] CRYPTO_EXPORT ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+ const std::string& username_hash,
+ base::OnceCallback<void(ScopedPK11Slot)> callback);
+
+// Closes the NSS DB for |username_hash| that was previously opened by the
+// *Initialize*ForChromeOSUser functions.
+CRYPTO_EXPORT void CloseChromeOSUserForTesting(
+ const std::string& username_hash);
+#endif // defined(OS_CHROMEOS)
+
+} // namespace crypto
+
+#endif // CRYPTO_NSS_UTIL_INTERNAL_H_
diff --git a/crypto/nss_util_unittest.cc b/crypto/nss_util_unittest.cc
new file mode 100644
index 0000000..8b37034
--- /dev/null
+++ b/crypto/nss_util_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/nss_util.h"
+
+#include <prtime.h>
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+TEST(NSSUtilTest, PRTimeConversion) {
+ EXPECT_EQ(base::Time::UnixEpoch(), PRTimeToBaseTime(0));
+ EXPECT_EQ(0, BaseTimeToPRTime(base::Time::UnixEpoch()));
+
+ PRExplodedTime prxtime;
+ prxtime.tm_params.tp_gmt_offset = 0;
+ prxtime.tm_params.tp_dst_offset = 0;
+ base::Time::Exploded exploded;
+ exploded.year = prxtime.tm_year = 2011;
+ exploded.month = 12;
+ prxtime.tm_month = 11;
+ // PRExplodedTime::tm_wday is a smaller type than Exploded::day_of_week, so
+ // assigning the two in this order instead of the reverse avoids potential
+ // warnings about type downcasting.
+ exploded.day_of_week = prxtime.tm_wday = 0; // Should be unused.
+ exploded.day_of_month = prxtime.tm_mday = 10;
+ exploded.hour = prxtime.tm_hour = 2;
+ exploded.minute = prxtime.tm_min = 52;
+ exploded.second = prxtime.tm_sec = 19;
+ exploded.millisecond = 342;
+ prxtime.tm_usec = 342000;
+
+ PRTime pr_time = PR_ImplodeTime(&prxtime);
+ base::Time base_time = base::Time::FromUTCExploded(exploded);
+
+ EXPECT_EQ(base_time, PRTimeToBaseTime(pr_time));
+ EXPECT_EQ(pr_time, BaseTimeToPRTime(base_time));
+}
+
+} // namespace crypto
diff --git a/crypto/openssl_util.cc b/crypto/openssl_util.cc
new file mode 100644
index 0000000..8051fb2
--- /dev/null
+++ b/crypto/openssl_util.cc
@@ -0,0 +1,62 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/openssl_util.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/cpu.h>
+#else
+#include <openssl/ssl.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+
+namespace crypto {
+
+namespace {
+
+// Callback routine for OpenSSL to print error messages. |str| is a
+// NULL-terminated string of length |len| containing diagnostic information
+// such as the library, function and reason for the error, the file and line
+// where the error originated, plus potentially any context-specific
+// information about the error. |context| contains a pointer to user-supplied
+// data, which is currently unused.
+// If this callback returns a value <= 0, OpenSSL will stop processing the
+// error queue and return, otherwise it will continue calling this function
+// until all errors have been removed from the queue.
+int OpenSSLErrorCallback(const char* str, size_t len, void* context) {
+ DVLOG(1) << "\t" << base::StringPiece(str, len);
+ return 1;
+}
+
+} // namespace
+
+void EnsureOpenSSLInit() {
+#if defined(OPENSSL_IS_BORINGSSL)
+ // CRYPTO_library_init may be safely called concurrently.
+ CRYPTO_library_init();
+#else
+ SSL_library_init();
+#endif
+}
+
+void ClearOpenSSLERRStack(const base::Location& location) {
+ if (DCHECK_IS_ON() && VLOG_IS_ON(1)) {
+ uint32_t error_num = ERR_peek_error();
+ if (error_num == 0)
+ return;
+
+ DVLOG(1) << "OpenSSL ERR_get_error stack from " << location.ToString();
+ ERR_print_errors_cb(&OpenSSLErrorCallback, NULL);
+ } else {
+ ERR_clear_error();
+ }
+}
+
+} // namespace crypto
diff --git a/crypto/openssl_util.h b/crypto/openssl_util.h
new file mode 100644
index 0000000..5ba16b6
--- /dev/null
+++ b/crypto/openssl_util.h
@@ -0,0 +1,94 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_OPENSSL_UTIL_H_
+#define CRYPTO_OPENSSL_UTIL_H_
+
+#include <stddef.h>
+
+#include "base/location.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's
+// SHA256, HMAC, etc functions, adapting the buffer sizing rules to meet those
+// of the our base wrapper APIs.
+// This allows the library to write directly to the caller's buffer if it is of
+// sufficient size, but if not it will write to temporary |min_sized_buffer_|
+// of required size and then its content is automatically copied out on
+// destruction, with truncation as appropriate.
+template<int MIN_SIZE>
+class ScopedOpenSSLSafeSizeBuffer {
+ public:
+ ScopedOpenSSLSafeSizeBuffer(unsigned char* output, size_t output_len)
+ : output_(output),
+ output_len_(output_len) {
+ }
+
+ ScopedOpenSSLSafeSizeBuffer(const ScopedOpenSSLSafeSizeBuffer&) = delete;
+ ScopedOpenSSLSafeSizeBuffer& operator=(const ScopedOpenSSLSafeSizeBuffer&) = delete;
+
+ ~ScopedOpenSSLSafeSizeBuffer() {
+ if (output_len_ < MIN_SIZE) {
+ // Copy the temporary buffer out, truncating as needed.
+ memcpy(output_, min_sized_buffer_, output_len_);
+ }
+ // else... any writing already happened directly into |output_|.
+ }
+
+ unsigned char* safe_buffer() {
+ return output_len_ < MIN_SIZE ? min_sized_buffer_ : output_;
+ }
+
+ private:
+ // Pointer to the caller's data area and its associated size, where data
+ // written via safe_buffer() will [eventually] end up.
+ unsigned char* output_;
+ size_t output_len_;
+
+ // Temporary buffer writen into in the case where the caller's
+ // buffer is not of sufficient size.
+ unsigned char min_sized_buffer_[MIN_SIZE];
+};
+
+// Initialize OpenSSL if it isn't already initialized. This must be called
+// before any other OpenSSL functions though it is safe and cheap to call this
+// multiple times.
+// This function is thread-safe, and OpenSSL will only ever be initialized once.
+// OpenSSL will be properly shut down on program exit.
+CRYPTO_EXPORT void EnsureOpenSSLInit();
+
+// Drains the OpenSSL ERR_get_error stack. On a debug build the error codes
+// are send to VLOG(1), on a release build they are disregarded. In most
+// cases you should pass FROM_HERE as the |location|.
+CRYPTO_EXPORT void ClearOpenSSLERRStack(const base::Location& location);
+
+// Place an instance of this class on the call stack to automatically clear
+// the OpenSSL error stack on function exit.
+class OpenSSLErrStackTracer {
+ public:
+ // Pass FROM_HERE as |location|, to help track the source of OpenSSL error
+ // messages. Note any diagnostic emitted will be tagged with the location of
+ // the constructor call as it's not possible to trace a destructor's callsite.
+ explicit OpenSSLErrStackTracer(const base::Location& location)
+ : location_(location) {
+ EnsureOpenSSLInit();
+ }
+
+ OpenSSLErrStackTracer() = delete;
+ OpenSSLErrStackTracer(const OpenSSLErrStackTracer&) = delete;
+ OpenSSLErrStackTracer& operator=(const OpenSSLErrStackTracer&) = delete;
+
+ ~OpenSSLErrStackTracer() {
+ ClearOpenSSLERRStack(location_);
+ }
+
+ private:
+ const base::Location location_;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_OPENSSL_UTIL_H_
diff --git a/crypto/p224.cc b/crypto/p224.cc
new file mode 100644
index 0000000..199f98e
--- /dev/null
+++ b/crypto/p224.cc
@@ -0,0 +1,747 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is an implementation of the P224 elliptic curve group. It's written to
+// be short and simple rather than fast, although it's still constant-time.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+#include "crypto/p224.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "base/sys_byteorder.h"
+
+namespace {
+
+using base::HostToNet32;
+using base::NetToHost32;
+
+// Field element functions.
+//
+// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1.
+//
+// Field elements are represented by a FieldElement, which is a typedef to an
+// array of 8 uint32_t's. The value of a FieldElement, a, is:
+// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7]
+//
+// Using 28-bit limbs means that there's only 4 bits of headroom, which is less
+// than we would really like. But it has the useful feature that we hit 2**224
+// exactly, making the reflections during a reduce much nicer.
+
+using crypto::p224::FieldElement;
+
+// kP is the P224 prime.
+const FieldElement kP = {
+ 1, 0, 0, 268431360,
+ 268435455, 268435455, 268435455, 268435455,
+};
+
+void Contract(FieldElement* inout);
+
+// IsZero returns 0xffffffff if a == 0 mod p and 0 otherwise.
+uint32_t IsZero(const FieldElement& a) {
+ FieldElement minimal;
+ memcpy(&minimal, &a, sizeof(minimal));
+ Contract(&minimal);
+
+ uint32_t is_zero = 0, is_p = 0;
+ for (unsigned i = 0; i < 8; i++) {
+ is_zero |= minimal[i];
+ is_p |= minimal[i] - kP[i];
+ }
+
+ // If either is_zero or is_p is 0, then we should return 1.
+ is_zero |= is_zero >> 16;
+ is_zero |= is_zero >> 8;
+ is_zero |= is_zero >> 4;
+ is_zero |= is_zero >> 2;
+ is_zero |= is_zero >> 1;
+
+ is_p |= is_p >> 16;
+ is_p |= is_p >> 8;
+ is_p |= is_p >> 4;
+ is_p |= is_p >> 2;
+ is_p |= is_p >> 1;
+
+ // For is_zero and is_p, the LSB is 0 iff all the bits are zero.
+ is_zero &= is_p & 1;
+ is_zero = (~is_zero) << 31;
+ is_zero = static_cast<int32_t>(is_zero) >> 31;
+ return is_zero;
+}
+
+// Add computes *out = a+b
+//
+// a[i] + b[i] < 2**32
+void Add(FieldElement* out, const FieldElement& a, const FieldElement& b) {
+ for (int i = 0; i < 8; i++) {
+ (*out)[i] = a[i] + b[i];
+ }
+}
+
+static const uint32_t kTwo31p3 = (1u << 31) + (1u << 3);
+static const uint32_t kTwo31m3 = (1u << 31) - (1u << 3);
+static const uint32_t kTwo31m15m3 = (1u << 31) - (1u << 15) - (1u << 3);
+// kZero31ModP is 0 mod p where bit 31 is set in all limbs so that we can
+// subtract smaller amounts without underflow. See the section "Subtraction" in
+// [1] for why.
+static const FieldElement kZero31ModP = {
+ kTwo31p3, kTwo31m3, kTwo31m3, kTwo31m15m3,
+ kTwo31m3, kTwo31m3, kTwo31m3, kTwo31m3
+};
+
+// Subtract computes *out = a-b
+//
+// a[i], b[i] < 2**30
+// out[i] < 2**32
+void Subtract(FieldElement* out, const FieldElement& a, const FieldElement& b) {
+ for (int i = 0; i < 8; i++) {
+ // See the section on "Subtraction" in [1] for details.
+ (*out)[i] = a[i] + kZero31ModP[i] - b[i];
+ }
+}
+
+static const uint64_t kTwo63p35 = (1ull << 63) + (1ull << 35);
+static const uint64_t kTwo63m35 = (1ull << 63) - (1ull << 35);
+static const uint64_t kTwo63m35m19 = (1ull << 63) - (1ull << 35) - (1ull << 19);
+// kZero63ModP is 0 mod p where bit 63 is set in all limbs. See the section
+// "Subtraction" in [1] for why.
+static const uint64_t kZero63ModP[8] = {
+ kTwo63p35, kTwo63m35, kTwo63m35, kTwo63m35,
+ kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35,
+};
+
+static const uint32_t kBottom28Bits = 0xfffffff;
+
+// LargeFieldElement also represents an element of the field. The limbs are
+// still spaced 28-bits apart and in little-endian order. So the limbs are at
+// 0, 28, 56, ..., 392 bits, each 64-bits wide.
+typedef uint64_t LargeFieldElement[15];
+
+// ReduceLarge converts a LargeFieldElement to a FieldElement.
+//
+// in[i] < 2**62
+void ReduceLarge(FieldElement* out, LargeFieldElement* inptr) {
+ LargeFieldElement& in(*inptr);
+
+ for (int i = 0; i < 8; i++) {
+ in[i] += kZero63ModP[i];
+ }
+
+ // Eliminate the coefficients at 2**224 and greater while maintaining the
+ // same value mod p.
+ for (int i = 14; i >= 8; i--) {
+ in[i-8] -= in[i]; // reflection off the "+1" term of p.
+ in[i-5] += (in[i] & 0xffff) << 12; // part of the "-2**96" reflection.
+ in[i-4] += in[i] >> 16; // the rest of the "-2**96" reflection.
+ }
+ in[8] = 0;
+ // in[0..8] < 2**64
+
+ // As the values become small enough, we start to store them in |out| and use
+ // 32-bit operations.
+ for (int i = 1; i < 8; i++) {
+ in[i+1] += in[i] >> 28;
+ (*out)[i] = static_cast<uint32_t>(in[i] & kBottom28Bits);
+ }
+ // Eliminate the term at 2*224 that we introduced while keeping the same
+ // value mod p.
+ in[0] -= in[8]; // reflection off the "+1" term of p.
+ (*out)[3] += static_cast<uint32_t>(in[8] & 0xffff) << 12; // "-2**96" term
+ (*out)[4] += static_cast<uint32_t>(in[8] >> 16); // rest of "-2**96" term
+ // in[0] < 2**64
+ // out[3] < 2**29
+ // out[4] < 2**29
+ // out[1,2,5..7] < 2**28
+
+ (*out)[0] = static_cast<uint32_t>(in[0] & kBottom28Bits);
+ (*out)[1] += static_cast<uint32_t>((in[0] >> 28) & kBottom28Bits);
+ (*out)[2] += static_cast<uint32_t>(in[0] >> 56);
+ // out[0] < 2**28
+ // out[1..4] < 2**29
+ // out[5..7] < 2**28
+}
+
+// Mul computes *out = a*b
+//
+// a[i] < 2**29, b[i] < 2**30 (or vice versa)
+// out[i] < 2**29
+void Mul(FieldElement* out, const FieldElement& a, const FieldElement& b) {
+ LargeFieldElement tmp;
+ memset(&tmp, 0, sizeof(tmp));
+
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 8; j++) {
+ tmp[i + j] += static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(b[j]);
+ }
+ }
+
+ ReduceLarge(out, &tmp);
+}
+
+// Square computes *out = a*a
+//
+// a[i] < 2**29
+// out[i] < 2**29
+void Square(FieldElement* out, const FieldElement& a) {
+ LargeFieldElement tmp;
+ memset(&tmp, 0, sizeof(tmp));
+
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j <= i; j++) {
+ uint64_t r = static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(a[j]);
+ if (i == j) {
+ tmp[i+j] += r;
+ } else {
+ tmp[i+j] += r << 1;
+ }
+ }
+ }
+
+ ReduceLarge(out, &tmp);
+}
+
+// Reduce reduces the coefficients of in_out to smaller bounds.
+//
+// On entry: a[i] < 2**31 + 2**30
+// On exit: a[i] < 2**29
+void Reduce(FieldElement* in_out) {
+ FieldElement& a = *in_out;
+
+ for (int i = 0; i < 7; i++) {
+ a[i+1] += a[i] >> 28;
+ a[i] &= kBottom28Bits;
+ }
+ uint32_t top = a[7] >> 28;
+ a[7] &= kBottom28Bits;
+
+ // top < 2**4
+ // Constant-time: mask = (top != 0) ? 0xffffffff : 0
+ uint32_t mask = top;
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask <<= 31;
+ mask = static_cast<uint32_t>(static_cast<int32_t>(mask) >> 31);
+
+ // Eliminate top while maintaining the same value mod p.
+ a[0] -= top;
+ a[3] += top << 12;
+
+ // We may have just made a[0] negative but, if we did, then we must
+ // have added something to a[3], thus it's > 2**12. Therefore we can
+ // carry down to a[0].
+ a[3] -= 1 & mask;
+ a[2] += mask & ((1<<28) - 1);
+ a[1] += mask & ((1<<28) - 1);
+ a[0] += mask & (1<<28);
+}
+
+// Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1), i.e.
+// Fermat's little theorem.
+void Invert(FieldElement* out, const FieldElement& in) {
+ FieldElement f1, f2, f3, f4;
+
+ Square(&f1, in); // 2
+ Mul(&f1, f1, in); // 2**2 - 1
+ Square(&f1, f1); // 2**3 - 2
+ Mul(&f1, f1, in); // 2**3 - 1
+ Square(&f2, f1); // 2**4 - 2
+ Square(&f2, f2); // 2**5 - 4
+ Square(&f2, f2); // 2**6 - 8
+ Mul(&f1, f1, f2); // 2**6 - 1
+ Square(&f2, f1); // 2**7 - 2
+ for (int i = 0; i < 5; i++) { // 2**12 - 2**6
+ Square(&f2, f2);
+ }
+ Mul(&f2, f2, f1); // 2**12 - 1
+ Square(&f3, f2); // 2**13 - 2
+ for (int i = 0; i < 11; i++) { // 2**24 - 2**12
+ Square(&f3, f3);
+ }
+ Mul(&f2, f3, f2); // 2**24 - 1
+ Square(&f3, f2); // 2**25 - 2
+ for (int i = 0; i < 23; i++) { // 2**48 - 2**24
+ Square(&f3, f3);
+ }
+ Mul(&f3, f3, f2); // 2**48 - 1
+ Square(&f4, f3); // 2**49 - 2
+ for (int i = 0; i < 47; i++) { // 2**96 - 2**48
+ Square(&f4, f4);
+ }
+ Mul(&f3, f3, f4); // 2**96 - 1
+ Square(&f4, f3); // 2**97 - 2
+ for (int i = 0; i < 23; i++) { // 2**120 - 2**24
+ Square(&f4, f4);
+ }
+ Mul(&f2, f4, f2); // 2**120 - 1
+ for (int i = 0; i < 6; i++) { // 2**126 - 2**6
+ Square(&f2, f2);
+ }
+ Mul(&f1, f1, f2); // 2**126 - 1
+ Square(&f1, f1); // 2**127 - 2
+ Mul(&f1, f1, in); // 2**127 - 1
+ for (int i = 0; i < 97; i++) { // 2**224 - 2**97
+ Square(&f1, f1);
+ }
+ Mul(out, f1, f3); // 2**224 - 2**96 - 1
+}
+
+// Contract converts a FieldElement to its minimal, distinguished form.
+//
+// On entry, in[i] < 2**29
+// On exit, in[i] < 2**28
+void Contract(FieldElement* inout) {
+ FieldElement& out = *inout;
+
+ // Reduce the coefficients to < 2**28.
+ for (int i = 0; i < 7; i++) {
+ out[i+1] += out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+ uint32_t top = out[7] >> 28;
+ out[7] &= kBottom28Bits;
+
+ // Eliminate top while maintaining the same value mod p.
+ out[0] -= top;
+ out[3] += top << 12;
+
+ // We may just have made out[0] negative. So we carry down. If we made
+ // out[0] negative then we know that out[3] is sufficiently positive
+ // because we just added to it.
+ for (int i = 0; i < 3; i++) {
+ uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31);
+ out[i] += (1 << 28) & mask;
+ out[i+1] -= 1 & mask;
+ }
+
+ // We might have pushed out[3] over 2**28 so we perform another, partial
+ // carry chain.
+ for (int i = 3; i < 7; i++) {
+ out[i+1] += out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+ top = out[7] >> 28;
+ out[7] &= kBottom28Bits;
+
+ // Eliminate top while maintaining the same value mod p.
+ out[0] -= top;
+ out[3] += top << 12;
+
+ // There are two cases to consider for out[3]:
+ // 1) The first time that we eliminated top, we didn't push out[3] over
+ // 2**28. In this case, the partial carry chain didn't change any values
+ // and top is zero.
+ // 2) We did push out[3] over 2**28 the first time that we eliminated top.
+ // The first value of top was in [0..16), therefore, prior to eliminating
+ // the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
+ // overflowing and being reduced by the second carry chain, out[3] <=
+ // 0xf000. Thus it cannot have overflowed when we eliminated top for the
+ // second time.
+
+ // Again, we may just have made out[0] negative, so do the same carry down.
+ // As before, if we made out[0] negative then we know that out[3] is
+ // sufficiently positive.
+ for (int i = 0; i < 3; i++) {
+ uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31);
+ out[i] += (1 << 28) & mask;
+ out[i+1] -= 1 & mask;
+ }
+
+ // The value is < 2**224, but maybe greater than p. In order to reduce to a
+ // unique, minimal value we see if the value is >= p and, if so, subtract p.
+
+ // First we build a mask from the top four limbs, which must all be
+ // equal to bottom28Bits if the whole value is >= p. If top_4_all_ones
+ // ends up with any zero bits in the bottom 28 bits, then this wasn't
+ // true.
+ uint32_t top_4_all_ones = 0xffffffffu;
+ for (int i = 4; i < 8; i++) {
+ top_4_all_ones &= out[i];
+ }
+ top_4_all_ones |= 0xf0000000;
+ // Now we replicate any zero bits to all the bits in top_4_all_ones.
+ top_4_all_ones &= top_4_all_ones >> 16;
+ top_4_all_ones &= top_4_all_ones >> 8;
+ top_4_all_ones &= top_4_all_ones >> 4;
+ top_4_all_ones &= top_4_all_ones >> 2;
+ top_4_all_ones &= top_4_all_ones >> 1;
+ top_4_all_ones =
+ static_cast<uint32_t>(static_cast<int32_t>(top_4_all_ones << 31) >> 31);
+
+ // Now we test whether the bottom three limbs are non-zero.
+ uint32_t bottom_3_non_zero = out[0] | out[1] | out[2];
+ bottom_3_non_zero |= bottom_3_non_zero >> 16;
+ bottom_3_non_zero |= bottom_3_non_zero >> 8;
+ bottom_3_non_zero |= bottom_3_non_zero >> 4;
+ bottom_3_non_zero |= bottom_3_non_zero >> 2;
+ bottom_3_non_zero |= bottom_3_non_zero >> 1;
+ bottom_3_non_zero =
+ static_cast<uint32_t>(static_cast<int32_t>(bottom_3_non_zero) >> 31);
+
+ // Everything depends on the value of out[3].
+ // If it's > 0xffff000 and top_4_all_ones != 0 then the whole value is >= p
+ // If it's = 0xffff000 and top_4_all_ones != 0 and bottom_3_non_zero != 0,
+ // then the whole value is >= p
+ // If it's < 0xffff000, then the whole value is < p
+ uint32_t n = out[3] - 0xffff000;
+ uint32_t out_3_equal = n;
+ out_3_equal |= out_3_equal >> 16;
+ out_3_equal |= out_3_equal >> 8;
+ out_3_equal |= out_3_equal >> 4;
+ out_3_equal |= out_3_equal >> 2;
+ out_3_equal |= out_3_equal >> 1;
+ out_3_equal =
+ ~static_cast<uint32_t>(static_cast<int32_t>(out_3_equal << 31) >> 31);
+
+ // If out[3] > 0xffff000 then n's MSB will be zero.
+ uint32_t out_3_gt =
+ ~static_cast<uint32_t>(static_cast<int32_t>(n << 31) >> 31);
+
+ uint32_t mask =
+ top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt);
+ out[0] -= 1 & mask;
+ out[3] -= 0xffff000 & mask;
+ out[4] -= 0xfffffff & mask;
+ out[5] -= 0xfffffff & mask;
+ out[6] -= 0xfffffff & mask;
+ out[7] -= 0xfffffff & mask;
+}
+
+
+// Group element functions.
+//
+// These functions deal with group elements. The group is an elliptic curve
+// group with a = -3 defined in FIPS 186-3, section D.2.2.
+
+using crypto::p224::Point;
+
+// kB is parameter of the elliptic curve.
+const FieldElement kB = {
+ 55967668, 11768882, 265861671, 185302395,
+ 39211076, 180311059, 84673715, 188764328,
+};
+
+void CopyConditional(Point* out, const Point& a, uint32_t mask);
+void DoubleJacobian(Point* out, const Point& a);
+
+// AddJacobian computes *out = a+b where a != b.
+void AddJacobian(Point *out,
+ const Point& a,
+ const Point& b) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+ FieldElement z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v;
+
+ uint32_t z1_is_zero = IsZero(a.z);
+ uint32_t z2_is_zero = IsZero(b.z);
+
+ // Z1Z1 = Z1²
+ Square(&z1z1, a.z);
+
+ // Z2Z2 = Z2²
+ Square(&z2z2, b.z);
+
+ // U1 = X1*Z2Z2
+ Mul(&u1, a.x, z2z2);
+
+ // U2 = X2*Z1Z1
+ Mul(&u2, b.x, z1z1);
+
+ // S1 = Y1*Z2*Z2Z2
+ Mul(&s1, b.z, z2z2);
+ Mul(&s1, a.y, s1);
+
+ // S2 = Y2*Z1*Z1Z1
+ Mul(&s2, a.z, z1z1);
+ Mul(&s2, b.y, s2);
+
+ // H = U2-U1
+ Subtract(&h, u2, u1);
+ Reduce(&h);
+ uint32_t x_equal = IsZero(h);
+
+ // I = (2*H)²
+ for (int k = 0; k < 8; k++) {
+ i[k] = h[k] << 1;
+ }
+ Reduce(&i);
+ Square(&i, i);
+
+ // J = H*I
+ Mul(&j, h, i);
+ // r = 2*(S2-S1)
+ Subtract(&r, s2, s1);
+ Reduce(&r);
+ uint32_t y_equal = IsZero(r);
+
+ if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) {
+ // The two input points are the same therefore we must use the dedicated
+ // doubling function as the slope of the line is undefined.
+ DoubleJacobian(out, a);
+ return;
+ }
+
+ for (int k = 0; k < 8; k++) {
+ r[k] <<= 1;
+ }
+ Reduce(&r);
+
+ // V = U1*I
+ Mul(&v, u1, i);
+
+ // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H
+ Add(&z1z1, z1z1, z2z2);
+ Add(&z2z2, a.z, b.z);
+ Reduce(&z2z2);
+ Square(&z2z2, z2z2);
+ Subtract(&out->z, z2z2, z1z1);
+ Reduce(&out->z);
+ Mul(&out->z, out->z, h);
+
+ // X3 = r²-J-2*V
+ for (int k = 0; k < 8; k++) {
+ z1z1[k] = v[k] << 1;
+ }
+ Add(&z1z1, j, z1z1);
+ Reduce(&z1z1);
+ Square(&out->x, r);
+ Subtract(&out->x, out->x, z1z1);
+ Reduce(&out->x);
+
+ // Y3 = r*(V-X3)-2*S1*J
+ for (int k = 0; k < 8; k++) {
+ s1[k] <<= 1;
+ }
+ Mul(&s1, s1, j);
+ Subtract(&z1z1, v, out->x);
+ Reduce(&z1z1);
+ Mul(&z1z1, z1z1, r);
+ Subtract(&out->y, z1z1, s1);
+ Reduce(&out->y);
+
+ CopyConditional(out, a, z2_is_zero);
+ CopyConditional(out, b, z1_is_zero);
+}
+
+// DoubleJacobian computes *out = a+a.
+void DoubleJacobian(Point* out, const Point& a) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+ FieldElement delta, gamma, beta, alpha, t;
+
+ Square(&delta, a.z);
+ Square(&gamma, a.y);
+ Mul(&beta, a.x, gamma);
+
+ // alpha = 3*(X1-delta)*(X1+delta)
+ Add(&t, a.x, delta);
+ for (int i = 0; i < 8; i++) {
+ t[i] += t[i] << 1;
+ }
+ Reduce(&t);
+ Subtract(&alpha, a.x, delta);
+ Reduce(&alpha);
+ Mul(&alpha, alpha, t);
+
+ // Z3 = (Y1+Z1)²-gamma-delta
+ Add(&out->z, a.y, a.z);
+ Reduce(&out->z);
+ Square(&out->z, out->z);
+ Subtract(&out->z, out->z, gamma);
+ Reduce(&out->z);
+ Subtract(&out->z, out->z, delta);
+ Reduce(&out->z);
+
+ // X3 = alpha²-8*beta
+ for (int i = 0; i < 8; i++) {
+ delta[i] = beta[i] << 3;
+ }
+ Reduce(&delta);
+ Square(&out->x, alpha);
+ Subtract(&out->x, out->x, delta);
+ Reduce(&out->x);
+
+ // Y3 = alpha*(4*beta-X3)-8*gamma²
+ for (int i = 0; i < 8; i++) {
+ beta[i] <<= 2;
+ }
+ Reduce(&beta);
+ Subtract(&beta, beta, out->x);
+ Reduce(&beta);
+ Square(&gamma, gamma);
+ for (int i = 0; i < 8; i++) {
+ gamma[i] <<= 3;
+ }
+ Reduce(&gamma);
+ Mul(&out->y, alpha, beta);
+ Subtract(&out->y, out->y, gamma);
+ Reduce(&out->y);
+}
+
+// CopyConditional sets *out=a if mask is 0xffffffff. mask must be either 0 of
+// 0xffffffff.
+void CopyConditional(Point* out, const Point& a, uint32_t mask) {
+ for (int i = 0; i < 8; i++) {
+ out->x[i] ^= mask & (a.x[i] ^ out->x[i]);
+ out->y[i] ^= mask & (a.y[i] ^ out->y[i]);
+ out->z[i] ^= mask & (a.z[i] ^ out->z[i]);
+ }
+}
+
+// ScalarMult calculates *out = a*scalar where scalar is a big-endian number of
+// length scalar_len and != 0.
+void ScalarMult(Point* out,
+ const Point& a,
+ const uint8_t* scalar,
+ size_t scalar_len) {
+ memset(out, 0, sizeof(*out));
+ Point tmp;
+
+ for (size_t i = 0; i < scalar_len; i++) {
+ for (unsigned int bit_num = 0; bit_num < 8; bit_num++) {
+ DoubleJacobian(out, *out);
+ uint32_t bit = static_cast<uint32_t>(static_cast<int32_t>(
+ (((scalar[i] >> (7 - bit_num)) & 1) << 31) >> 31));
+ AddJacobian(&tmp, a, *out);
+ CopyConditional(out, tmp, bit);
+ }
+ }
+}
+
+// Get224Bits reads 7 words from in and scatters their contents in
+// little-endian form into 8 words at out, 28 bits per output word.
+void Get224Bits(uint32_t* out, const uint32_t* in) {
+ out[0] = NetToHost32(in[6]) & kBottom28Bits;
+ out[1] = ((NetToHost32(in[5]) << 4) |
+ (NetToHost32(in[6]) >> 28)) & kBottom28Bits;
+ out[2] = ((NetToHost32(in[4]) << 8) |
+ (NetToHost32(in[5]) >> 24)) & kBottom28Bits;
+ out[3] = ((NetToHost32(in[3]) << 12) |
+ (NetToHost32(in[4]) >> 20)) & kBottom28Bits;
+ out[4] = ((NetToHost32(in[2]) << 16) |
+ (NetToHost32(in[3]) >> 16)) & kBottom28Bits;
+ out[5] = ((NetToHost32(in[1]) << 20) |
+ (NetToHost32(in[2]) >> 12)) & kBottom28Bits;
+ out[6] = ((NetToHost32(in[0]) << 24) |
+ (NetToHost32(in[1]) >> 8)) & kBottom28Bits;
+ out[7] = (NetToHost32(in[0]) >> 4) & kBottom28Bits;
+}
+
+// Put224Bits performs the inverse operation to Get224Bits: taking 28 bits from
+// each of 8 input words and writing them in big-endian order to 7 words at
+// out.
+void Put224Bits(uint32_t* out, const uint32_t* in) {
+ out[6] = HostToNet32((in[0] >> 0) | (in[1] << 28));
+ out[5] = HostToNet32((in[1] >> 4) | (in[2] << 24));
+ out[4] = HostToNet32((in[2] >> 8) | (in[3] << 20));
+ out[3] = HostToNet32((in[3] >> 12) | (in[4] << 16));
+ out[2] = HostToNet32((in[4] >> 16) | (in[5] << 12));
+ out[1] = HostToNet32((in[5] >> 20) | (in[6] << 8));
+ out[0] = HostToNet32((in[6] >> 24) | (in[7] << 4));
+}
+
+} // anonymous namespace
+
+namespace crypto {
+
+namespace p224 {
+
+bool Point::SetFromString(const base::StringPiece& in) {
+ if (in.size() != 2*28)
+ return false;
+ const uint32_t* inwords = reinterpret_cast<const uint32_t*>(in.data());
+ Get224Bits(x, inwords);
+ Get224Bits(y, inwords + 7);
+ memset(&z, 0, sizeof(z));
+ z[0] = 1;
+
+ // Check that the point is on the curve, i.e. that y² = x³ - 3x + b.
+ FieldElement lhs;
+ Square(&lhs, y);
+ Contract(&lhs);
+
+ FieldElement rhs;
+ Square(&rhs, x);
+ Mul(&rhs, x, rhs);
+
+ FieldElement three_x;
+ for (int i = 0; i < 8; i++) {
+ three_x[i] = x[i] * 3;
+ }
+ Reduce(&three_x);
+ Subtract(&rhs, rhs, three_x);
+ Reduce(&rhs);
+
+ ::Add(&rhs, rhs, kB);
+ Contract(&rhs);
+ return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
+}
+
+std::string Point::ToString() const {
+ FieldElement zinv, zinv_sq, xx, yy;
+
+ // If this is the point at infinity we return a string of all zeros.
+ if (IsZero(this->z)) {
+ static const char zeros[56] = {0};
+ return std::string(zeros, sizeof(zeros));
+ }
+
+ Invert(&zinv, this->z);
+ Square(&zinv_sq, zinv);
+ Mul(&xx, x, zinv_sq);
+ Mul(&zinv_sq, zinv_sq, zinv);
+ Mul(&yy, y, zinv_sq);
+
+ Contract(&xx);
+ Contract(&yy);
+
+ uint32_t outwords[14];
+ Put224Bits(outwords, xx);
+ Put224Bits(outwords + 7, yy);
+ return std::string(reinterpret_cast<const char*>(outwords), sizeof(outwords));
+}
+
+void ScalarMult(const Point& in, const uint8_t* scalar, Point* out) {
+ ::ScalarMult(out, in, scalar, 28);
+}
+
+// kBasePoint is the base point (generator) of the elliptic curve group.
+static const Point kBasePoint = {
+ {22813985, 52956513, 34677300, 203240812,
+ 12143107, 133374265, 225162431, 191946955},
+ {83918388, 223877528, 122119236, 123340192,
+ 266784067, 263504429, 146143011, 198407736},
+ {1, 0, 0, 0, 0, 0, 0, 0},
+};
+
+void ScalarBaseMult(const uint8_t* scalar, Point* out) {
+ ::ScalarMult(out, kBasePoint, scalar, 28);
+}
+
+void Add(const Point& a, const Point& b, Point* out) {
+ AddJacobian(out, a, b);
+}
+
+void Negate(const Point& in, Point* out) {
+ // Guide to elliptic curve cryptography, page 89 suggests that (X : X+Y : Z)
+ // is the negative in Jacobian coordinates, but it doesn't actually appear to
+ // be true in testing so this performs the negation in affine coordinates.
+ FieldElement zinv, zinv_sq, y;
+ Invert(&zinv, in.z);
+ Square(&zinv_sq, zinv);
+ Mul(&out->x, in.x, zinv_sq);
+ Mul(&zinv_sq, zinv_sq, zinv);
+ Mul(&y, in.y, zinv_sq);
+
+ Subtract(&out->y, kP, y);
+ Reduce(&out->y);
+
+ memset(&out->z, 0, sizeof(out->z));
+ out->z[0] = 1;
+}
+
+} // namespace p224
+
+} // namespace crypto
diff --git a/crypto/p224.h b/crypto/p224.h
new file mode 100644
index 0000000..4dcb67c
--- /dev/null
+++ b/crypto/p224.h
@@ -0,0 +1,64 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_P224_H_
+#define CRYPTO_P224_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// P224 implements an elliptic curve group, commonly known as P224 and defined
+// in FIPS 186-3, section D.2.2.
+namespace p224 {
+
+// An element of the field (ℤ/pℤ) is represented with 8, 28-bit limbs in
+// little endian order.
+typedef uint32_t FieldElement[8];
+
+struct CRYPTO_EXPORT Point {
+ // SetFromString the value of the point from the 56 byte, external
+ // representation. The external point representation is an (x, y) pair of a
+ // point on the curve. Each field element is represented as a big-endian
+ // number < p.
+ bool SetFromString(const base::StringPiece& in);
+
+ // ToString returns an external representation of the Point.
+ std::string ToString() const;
+
+ // An Point is represented in Jacobian form (x/z², y/z³).
+ FieldElement x, y, z;
+};
+
+// kScalarBytes is the number of bytes needed to represent an element of the
+// P224 field.
+static const size_t kScalarBytes = 28;
+
+// ScalarMult computes *out = in*scalar where scalar is a 28-byte, big-endian
+// number.
+void CRYPTO_EXPORT ScalarMult(const Point& in,
+ const uint8_t* scalar,
+ Point* out);
+
+// ScalarBaseMult computes *out = g*scalar where g is the base point of the
+// curve and scalar is a 28-byte, big-endian number.
+void CRYPTO_EXPORT ScalarBaseMult(const uint8_t* scalar, Point* out);
+
+// Add computes *out = a+b.
+void CRYPTO_EXPORT Add(const Point& a, const Point& b, Point* out);
+
+// Negate calculates out = -a;
+void CRYPTO_EXPORT Negate(const Point& a, Point* out);
+
+} // namespace p224
+
+} // namespace crypto
+
+#endif // CRYPTO_P224_H_
diff --git a/crypto/p224_spake.cc b/crypto/p224_spake.cc
new file mode 100644
index 0000000..9b6adf0
--- /dev/null
+++ b/crypto/p224_spake.cc
@@ -0,0 +1,268 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This code implements SPAKE2, a variant of EKE:
+// http://www.di.ens.fr/~pointche/pub.php?reference=AbPo04
+
+#include <crypto/p224_spake.h>
+
+#include <algorithm>
+
+#include <base/logging.h>
+#include <crypto/p224.h>
+#include <crypto/random.h>
+#include <crypto/secure_util.h>
+
+namespace {
+
+// The following two points (M and N in the protocol) are verifiable random
+// points on the curve and can be generated with the following code:
+
+// #include <stdint.h>
+// #include <stdio.h>
+// #include <string.h>
+//
+// #include <openssl/ec.h>
+// #include <openssl/obj_mac.h>
+// #include <openssl/sha.h>
+//
+// static const char kSeed1[] = "P224 point generation seed (M)";
+// static const char kSeed2[] = "P224 point generation seed (N)";
+//
+// void find_seed(const char* seed) {
+// SHA256_CTX sha256;
+// uint8_t digest[SHA256_DIGEST_LENGTH];
+//
+// SHA256_Init(&sha256);
+// SHA256_Update(&sha256, seed, strlen(seed));
+// SHA256_Final(digest, &sha256);
+//
+// BIGNUM x, y;
+// EC_GROUP* p224 = EC_GROUP_new_by_curve_name(NID_secp224r1);
+// EC_POINT* p = EC_POINT_new(p224);
+//
+// for (unsigned i = 0;; i++) {
+// BN_init(&x);
+// BN_bin2bn(digest, 28, &x);
+//
+// if (EC_POINT_set_compressed_coordinates_GFp(
+// p224, p, &x, digest[28] & 1, NULL)) {
+// BN_init(&y);
+// EC_POINT_get_affine_coordinates_GFp(p224, p, &x, &y, NULL);
+// char* x_str = BN_bn2hex(&x);
+// char* y_str = BN_bn2hex(&y);
+// printf("Found after %u iterations:\n%s\n%s\n", i, x_str, y_str);
+// OPENSSL_free(x_str);
+// OPENSSL_free(y_str);
+// BN_free(&x);
+// BN_free(&y);
+// break;
+// }
+//
+// SHA256_Init(&sha256);
+// SHA256_Update(&sha256, digest, sizeof(digest));
+// SHA256_Final(digest, &sha256);
+//
+// BN_free(&x);
+// }
+//
+// EC_POINT_free(p);
+// EC_GROUP_free(p224);
+// }
+//
+// int main() {
+// find_seed(kSeed1);
+// find_seed(kSeed2);
+// return 0;
+// }
+
+const crypto::p224::Point kM = {
+ {174237515, 77186811, 235213682, 33849492,
+ 33188520, 48266885, 177021753, 81038478},
+ {104523827, 245682244, 266509668, 236196369,
+ 28372046, 145351378, 198520366, 113345994},
+ {1, 0, 0, 0, 0, 0, 0, 0},
+};
+
+const crypto::p224::Point kN = {
+ {136176322, 263523628, 251628795, 229292285,
+ 5034302, 185981975, 171998428, 11653062},
+ {197567436, 51226044, 60372156, 175772188,
+ 42075930, 8083165, 160827401, 65097570},
+ {1, 0, 0, 0, 0, 0, 0, 0},
+};
+
+} // anonymous namespace
+
+namespace crypto {
+
+P224EncryptedKeyExchange::P224EncryptedKeyExchange(
+ PeerType peer_type, const base::StringPiece& password)
+ : state_(kStateInitial),
+ is_server_(peer_type == kPeerTypeServer) {
+ memset(&x_, 0, sizeof(x_));
+ memset(&expected_authenticator_, 0, sizeof(expected_authenticator_));
+
+ // x_ is a random scalar.
+ RandBytes(x_, sizeof(x_));
+
+ // Calculate |password| hash to get SPAKE password value.
+ SHA256HashString(std::string(password.data(), password.length()),
+ pw_, sizeof(pw_));
+
+ Init();
+}
+
+void P224EncryptedKeyExchange::Init() {
+ // X = g**x_
+ p224::Point X;
+ p224::ScalarBaseMult(x_, &X);
+
+ // The client masks the Diffie-Hellman value, X, by adding M**pw and the
+ // server uses N**pw.
+ p224::Point MNpw;
+ p224::ScalarMult(is_server_ ? kN : kM, pw_, &MNpw);
+
+ // X* = X + (N|M)**pw
+ p224::Point Xstar;
+ p224::Add(X, MNpw, &Xstar);
+
+ next_message_ = Xstar.ToString();
+}
+
+const std::string& P224EncryptedKeyExchange::GetNextMessage() {
+ if (state_ == kStateInitial) {
+ state_ = kStateRecvDH;
+ return next_message_;
+ } else if (state_ == kStateSendHash) {
+ state_ = kStateRecvHash;
+ return next_message_;
+ }
+
+ LOG(FATAL) << "P224EncryptedKeyExchange::GetNextMessage called in"
+ " bad state " << state_;
+ next_message_ = "";
+ return next_message_;
+}
+
+P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage(
+ const base::StringPiece& message) {
+ if (state_ == kStateRecvHash) {
+ // This is the final state of the protocol: we are reading the peer's
+ // authentication hash and checking that it matches the one that we expect.
+ if (message.size() != sizeof(expected_authenticator_)) {
+ error_ = "peer's hash had an incorrect size";
+ return kResultFailed;
+ }
+ if (!SecureMemEqual(message.data(), expected_authenticator_,
+ message.size())) {
+ error_ = "peer's hash had incorrect value";
+ return kResultFailed;
+ }
+ state_ = kStateDone;
+ return kResultSuccess;
+ }
+
+ if (state_ != kStateRecvDH) {
+ LOG(FATAL) << "P224EncryptedKeyExchange::ProcessMessage called in"
+ " bad state " << state_;
+ error_ = "internal error";
+ return kResultFailed;
+ }
+
+ // Y* is the other party's masked, Diffie-Hellman value.
+ p224::Point Ystar;
+ if (!Ystar.SetFromString(message)) {
+ error_ = "failed to parse peer's masked Diffie-Hellman value";
+ return kResultFailed;
+ }
+
+ // We calculate the mask value: (N|M)**pw
+ p224::Point MNpw, minus_MNpw, Y, k;
+ p224::ScalarMult(is_server_ ? kM : kN, pw_, &MNpw);
+ p224::Negate(MNpw, &minus_MNpw);
+
+ // Y = Y* - (N|M)**pw
+ p224::Add(Ystar, minus_MNpw, &Y);
+
+ // K = Y**x_
+ p224::ScalarMult(Y, x_, &k);
+
+ // If everything worked out, then K is the same for both parties.
+ key_ = k.ToString();
+
+ std::string client_masked_dh, server_masked_dh;
+ if (is_server_) {
+ client_masked_dh = std::string(message);
+ server_masked_dh = next_message_;
+ } else {
+ client_masked_dh = next_message_;
+ server_masked_dh = std::string(message);
+ }
+
+ // Now we calculate the hashes that each side will use to prove to the other
+ // that they derived the correct value for K.
+ uint8_t client_hash[kSHA256Length], server_hash[kSHA256Length];
+ CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, key_,
+ client_hash);
+ CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, key_,
+ server_hash);
+
+ const uint8_t* my_hash = is_server_ ? server_hash : client_hash;
+ const uint8_t* their_hash = is_server_ ? client_hash : server_hash;
+
+ next_message_ =
+ std::string(reinterpret_cast<const char*>(my_hash), kSHA256Length);
+ memcpy(expected_authenticator_, their_hash, kSHA256Length);
+ state_ = kStateSendHash;
+ return kResultPending;
+}
+
+void P224EncryptedKeyExchange::CalculateHash(
+ PeerType peer_type,
+ const std::string& client_masked_dh,
+ const std::string& server_masked_dh,
+ const std::string& k,
+ uint8_t* out_digest) {
+ std::string hash_contents;
+
+ if (peer_type == kPeerTypeServer) {
+ hash_contents = "server";
+ } else {
+ hash_contents = "client";
+ }
+
+ hash_contents += client_masked_dh;
+ hash_contents += server_masked_dh;
+ hash_contents +=
+ std::string(reinterpret_cast<const char *>(pw_), sizeof(pw_));
+ hash_contents += k;
+
+ SHA256HashString(hash_contents, out_digest, kSHA256Length);
+}
+
+const std::string& P224EncryptedKeyExchange::error() const {
+ return error_;
+}
+
+const std::string& P224EncryptedKeyExchange::GetKey() const {
+ DCHECK_EQ(state_, kStateDone);
+ return GetUnverifiedKey();
+}
+
+const std::string& P224EncryptedKeyExchange::GetUnverifiedKey() const {
+ // Key is already final when state is kStateSendHash. Subsequent states are
+ // used only for verification of the key. Some users may combine verification
+ // with sending verifiable data instead of |expected_authenticator_|.
+ DCHECK_GE(state_, kStateSendHash);
+ return key_;
+}
+
+void P224EncryptedKeyExchange::SetXForTesting(const std::string& x) {
+ memset(&x_, 0, sizeof(x_));
+ memcpy(&x_, x.data(), std::min(x.size(), sizeof(x_)));
+ Init();
+}
+
+} // namespace crypto
diff --git a/crypto/p224_spake.h b/crypto/p224_spake.h
new file mode 100644
index 0000000..290c562
--- /dev/null
+++ b/crypto/p224_spake.h
@@ -0,0 +1,127 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_P224_SPAKE_H_
+#define CRYPTO_P224_SPAKE_H_
+
+#include <crypto/p224.h>
+#include <crypto/sha2.h>
+#include <stdint.h>
+
+#include "base/gtest_prod_util.h"
+#include "base/strings/string_piece.h"
+
+namespace crypto {
+
+// P224EncryptedKeyExchange implements SPAKE2, a variant of Encrypted
+// Key Exchange. It allows two parties that have a secret common
+// password to establish a common secure key by exchanging messages
+// over an insecure channel without disclosing the password.
+//
+// The password can be low entropy as authenticating with an attacker only
+// gives the attacker a one-shot password oracle. No other information about
+// the password is leaked. (However, you must be sure to limit the number of
+// permitted authentication attempts otherwise they get many one-shot oracles.)
+//
+// The protocol requires several RTTs (actually two, but you shouldn't assume
+// that.) To use the object, call GetNextMessage() and pass that message to the
+// peer. Get a message from the peer and feed it into ProcessMessage. Then
+// examine the return value of ProcessMessage:
+// kResultPending: Another round is required. Call GetNextMessage and repeat.
+// kResultFailed: The authentication has failed. You can get a human readable
+// error message by calling error().
+// kResultSuccess: The authentication was successful.
+//
+// In each exchange, each peer always sends a message.
+class CRYPTO_EXPORT P224EncryptedKeyExchange {
+ public:
+ enum Result {
+ kResultPending,
+ kResultFailed,
+ kResultSuccess,
+ };
+
+ // PeerType's values are named client and server due to convention. But
+ // they could be called "A" and "B" as far as the protocol is concerned so
+ // long as the two parties don't both get the same label.
+ enum PeerType {
+ kPeerTypeClient,
+ kPeerTypeServer,
+ };
+
+ // peer_type: the type of the local authentication party.
+ // password: secret session password. Both parties to the
+ // authentication must pass the same value. For the case of a
+ // TLS connection, see RFC 5705.
+ P224EncryptedKeyExchange(PeerType peer_type,
+ const base::StringPiece& password);
+
+ // GetNextMessage returns a byte string which must be passed to the other
+ // party in the authentication.
+ const std::string& GetNextMessage();
+
+ // ProcessMessage processes a message which must have been generated by a
+ // call to GetNextMessage() by the other party.
+ Result ProcessMessage(const base::StringPiece& message);
+
+ // In the event that ProcessMessage() returns kResultFailed, error will
+ // return a human readable error message.
+ const std::string& error() const;
+
+ // The key established as result of the key exchange. Must be called
+ // at then end after ProcessMessage() returns kResultSuccess.
+ const std::string& GetKey() const;
+
+ // The key established as result of the key exchange. Can be called after
+ // the first ProcessMessage()
+ const std::string& GetUnverifiedKey() const;
+
+ private:
+ // The authentication state machine is very simple and each party proceeds
+ // through each of these states, in order.
+ enum State {
+ kStateInitial,
+ kStateRecvDH,
+ kStateSendHash,
+ kStateRecvHash,
+ kStateDone,
+ };
+
+ FRIEND_TEST_ALL_PREFIXES(MutualAuth, ExpectedValues);
+
+ void Init();
+
+ // Sets internal random scalar. Should be used by tests only.
+ void SetXForTesting(const std::string& x);
+
+ State state_;
+ const bool is_server_;
+ // next_message_ contains a value for GetNextMessage() to return.
+ std::string next_message_;
+ std::string error_;
+
+ // CalculateHash computes the verification hash for the given peer and writes
+ // |kSHA256Length| bytes at |out_digest|.
+ void CalculateHash(PeerType peer_type,
+ const std::string& client_masked_dh,
+ const std::string& server_masked_dh,
+ const std::string& k,
+ uint8_t* out_digest);
+
+ // x_ is the secret Diffie-Hellman exponent (see paper referenced in .cc
+ // file).
+ uint8_t x_[p224::kScalarBytes];
+ // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32_t,
+ // big-endian length prefix (see paper referenced in .cc file).
+ uint8_t pw_[p224::kScalarBytes];
+ // expected_authenticator_ is used to store the hash value expected from the
+ // other party.
+ uint8_t expected_authenticator_[kSHA256Length];
+
+ std::string key_;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_P224_SPAKE_H_
diff --git a/crypto/p224_spake_unittest.cc b/crypto/p224_spake_unittest.cc
new file mode 100644
index 0000000..d99dfc0
--- /dev/null
+++ b/crypto/p224_spake_unittest.cc
@@ -0,0 +1,177 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/p224_spake.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+namespace {
+
+std::string HexEncodeString(const std::string& binary_data) {
+ return base::HexEncode(binary_data.c_str(), binary_data.size());
+}
+
+bool RunExchange(P224EncryptedKeyExchange* client,
+ P224EncryptedKeyExchange* server,
+ bool is_password_same) {
+ for (;;) {
+ std::string client_message, server_message;
+ client_message = client->GetNextMessage();
+ server_message = server->GetNextMessage();
+
+ P224EncryptedKeyExchange::Result client_result, server_result;
+ client_result = client->ProcessMessage(server_message);
+ server_result = server->ProcessMessage(client_message);
+
+ // Check that we never hit the case where only one succeeds.
+ EXPECT_EQ(client_result == P224EncryptedKeyExchange::kResultSuccess,
+ server_result == P224EncryptedKeyExchange::kResultSuccess);
+
+ if (client_result == P224EncryptedKeyExchange::kResultFailed ||
+ server_result == P224EncryptedKeyExchange::kResultFailed) {
+ return false;
+ }
+
+ EXPECT_EQ(is_password_same,
+ client->GetUnverifiedKey() == server->GetUnverifiedKey());
+
+ if (client_result == P224EncryptedKeyExchange::kResultSuccess &&
+ server_result == P224EncryptedKeyExchange::kResultSuccess) {
+ return true;
+ }
+
+ EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, client_result);
+ EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, server_result);
+ }
+}
+
+const char kPassword[] = "foo";
+
+} // namespace
+
+TEST(MutualAuth, CorrectAuth) {
+ P224EncryptedKeyExchange client(
+ P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
+ P224EncryptedKeyExchange server(
+ P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
+
+ EXPECT_TRUE(RunExchange(&client, &server, true));
+ EXPECT_EQ(client.GetKey(), server.GetKey());
+}
+
+TEST(MutualAuth, IncorrectPassword) {
+ P224EncryptedKeyExchange client(
+ P224EncryptedKeyExchange::kPeerTypeClient,
+ kPassword);
+ P224EncryptedKeyExchange server(
+ P224EncryptedKeyExchange::kPeerTypeServer,
+ "wrongpassword");
+
+ EXPECT_FALSE(RunExchange(&client, &server, false));
+}
+
+TEST(MutualAuth, ExpectedValues) {
+ P224EncryptedKeyExchange client(P224EncryptedKeyExchange::kPeerTypeClient,
+ kPassword);
+ client.SetXForTesting("Client x");
+ P224EncryptedKeyExchange server(P224EncryptedKeyExchange::kPeerTypeServer,
+ kPassword);
+ server.SetXForTesting("Server x");
+
+ std::string client_message = client.GetNextMessage();
+ EXPECT_EQ(
+ "3508EF7DECC8AB9F9C439FBB0154288BBECC0A82E8448F4CF29554EB"
+ "BE9D486686226255EAD1D077C635B1A41F46AC91D7F7F32CED9EC3E0",
+ HexEncodeString(client_message));
+
+ std::string server_message = server.GetNextMessage();
+ EXPECT_EQ(
+ "A3088C18B75D2C2B107105661AEC85424777475EB29F1DDFB8C14AFB"
+ "F1603D0DF38413A00F420ACF2059E7997C935F5A957A193D09A2B584",
+ HexEncodeString(server_message));
+
+ EXPECT_EQ(P224EncryptedKeyExchange::kResultPending,
+ client.ProcessMessage(server_message));
+ EXPECT_EQ(P224EncryptedKeyExchange::kResultPending,
+ server.ProcessMessage(client_message));
+
+ EXPECT_EQ(client.GetUnverifiedKey(), server.GetUnverifiedKey());
+ // Must stay the same. External implementations should be able to pair with.
+ EXPECT_EQ(
+ "CE7CCFC435CDA4F01EC8826788B1F8B82EF7D550A34696B371096E64"
+ "C487D4FE193F7D1A6FF6820BC7F807796BA3889E8F999BBDEFC32FFA",
+ HexEncodeString(server.GetUnverifiedKey()));
+
+ EXPECT_TRUE(RunExchange(&client, &server, true));
+ EXPECT_EQ(client.GetKey(), server.GetKey());
+}
+
+TEST(MutualAuth, Fuzz) {
+ static const unsigned kIterations = 40;
+
+ for (unsigned i = 0; i < kIterations; i++) {
+ P224EncryptedKeyExchange client(
+ P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
+ P224EncryptedKeyExchange server(
+ P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
+
+ // We'll only be testing small values of i, but we don't want that to bias
+ // the test coverage. So we disperse the value of i by multiplying by the
+ // FNV, 32-bit prime, producing a poor-man's PRNG.
+ const uint32_t rand = i * 16777619;
+
+ for (unsigned round = 0;; round++) {
+ std::string client_message, server_message;
+ client_message = client.GetNextMessage();
+ server_message = server.GetNextMessage();
+
+ if ((rand & 1) == round) {
+ const bool server_or_client = rand & 2;
+ std::string* m = server_or_client ? &server_message : &client_message;
+ if (rand & 4) {
+ // Truncate
+ *m = m->substr(0, (i >> 3) % m->size());
+ } else {
+ // Corrupt
+ const size_t bits = m->size() * 8;
+ const size_t bit_to_corrupt = (rand >> 3) % bits;
+ const_cast<char*>(m->data())[bit_to_corrupt / 8] ^=
+ 1 << (bit_to_corrupt % 8);
+ }
+ }
+
+ P224EncryptedKeyExchange::Result client_result, server_result;
+ client_result = client.ProcessMessage(server_message);
+ server_result = server.ProcessMessage(client_message);
+
+ // If we have corrupted anything, we expect the authentication to fail,
+ // although one side can succeed if we happen to corrupt the second round
+ // message to the other.
+ ASSERT_FALSE(
+ client_result == P224EncryptedKeyExchange::kResultSuccess &&
+ server_result == P224EncryptedKeyExchange::kResultSuccess);
+
+ if (client_result == P224EncryptedKeyExchange::kResultFailed ||
+ server_result == P224EncryptedKeyExchange::kResultFailed) {
+ break;
+ }
+
+ ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
+ client_result);
+ ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
+ server_result);
+ }
+ }
+}
+
+} // namespace crypto
diff --git a/crypto/p224_unittest.cc b/crypto/p224_unittest.cc
new file mode 100644
index 0000000..43df346
--- /dev/null
+++ b/crypto/p224_unittest.cc
@@ -0,0 +1,824 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "crypto/p224.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+using p224::Point;
+
+// kBasePointExternal is the P224 base point in external representation.
+static const uint8_t kBasePointExternal[56] = {
+ 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9,
+ 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
+ 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb,
+ 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64,
+ 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34,
+};
+
+// TestVector represents a test of scalar multiplication of the base point.
+// |scalar| is a big-endian scalar and |affine| is the external representation
+// of g*scalar.
+struct TestVector {
+ uint8_t scalar[28];
+ uint8_t affine[28 * 2];
+};
+
+static const int kNumNISTTestVectors = 52;
+
+// kNISTTestVectors are the NIST test vectors for P224.
+static const TestVector kNISTTestVectors[kNumNISTTestVectors] = {
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01},
+ {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
+ 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
+ 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
+ 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88,
+ 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6,
+ 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64,
+ 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, },
+
+ {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67,
+ 0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88,
+ 0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd,
+ 0x1a, 0x70, 0x4f, 0xa6, 0x1c, 0x2b, 0x76, 0xa7,
+ 0xbc, 0x25, 0xe7, 0x70, 0x2a, 0x70, 0x4f, 0xa9,
+ 0x86, 0x89, 0x28, 0x49, 0xfc, 0xa6, 0x29, 0x48,
+ 0x7a, 0xcf, 0x37, 0x09, 0xd2, 0xe4, 0xe8, 0xbb,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, },
+ {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3,
+ 0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc,
+ 0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08,
+ 0xfd, 0x89, 0x6d, 0x04, 0xa3, 0xf7, 0xf0, 0x3c,
+ 0xad, 0xd0, 0xbe, 0x44, 0x4c, 0x0a, 0xa5, 0x68,
+ 0x30, 0x13, 0x0d, 0xdf, 0x77, 0xd3, 0x17, 0x34,
+ 0x4e, 0x1a, 0xf3, 0x59, 0x19, 0x81, 0xa9, 0x25,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, },
+ {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45,
+ 0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02,
+ 0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e,
+ 0x40, 0x44, 0x73, 0x01, 0x04, 0x82, 0x58, 0x0a,
+ 0x0e, 0xc5, 0xbc, 0x47, 0xe8, 0x8b, 0xc8, 0xc3,
+ 0x78, 0x63, 0x2c, 0xd1, 0x96, 0xcb, 0x3f, 0xa0,
+ 0x58, 0xa7, 0x11, 0x4e, 0xb0, 0x30, 0x54, 0xc9,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, },
+ {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07,
+ 0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90,
+ 0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75,
+ 0x26, 0xf0, 0x11, 0xaa, 0x27, 0xe8, 0xbf, 0xf1,
+ 0x74, 0x56, 0x35, 0xec, 0x5b, 0xa0, 0xc9, 0xf1,
+ 0xc2, 0xed, 0xe1, 0x54, 0x14, 0xc6, 0x50, 0x7d,
+ 0x29, 0xff, 0xe3, 0x7e, 0x79, 0x0a, 0x07, 0x9b,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, },
+ {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f,
+ 0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d,
+ 0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c,
+ 0x57, 0x11, 0x24, 0x08, 0x89, 0xfa, 0xf0, 0xcc,
+ 0xb7, 0x50, 0xd9, 0x9b, 0x55, 0x3c, 0x57, 0x4f,
+ 0xad, 0x7e, 0xcf, 0xb0, 0x43, 0x85, 0x86, 0xeb,
+ 0x39, 0x52, 0xaf, 0x5b, 0x4b, 0x15, 0x3c, 0x7e,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07, },
+ {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5,
+ 0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23,
+ 0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24,
+ 0xa0, 0x3c, 0x3e, 0x28, 0x0f, 0x3a, 0x30, 0x08,
+ 0x54, 0x97, 0xf2, 0xf6, 0x11, 0xee, 0x25, 0x17,
+ 0xb1, 0x63, 0xef, 0x8c, 0x53, 0xb7, 0x15, 0xd1,
+ 0x8b, 0xb4, 0xe4, 0x80, 0x8d, 0x02, 0xb9, 0x63,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, },
+ {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31,
+ 0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0,
+ 0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b,
+ 0x55, 0x57, 0x15, 0x50, 0x04, 0x6d, 0xcd, 0x3e,
+ 0xa5, 0xc4, 0x38, 0x98, 0xc5, 0xc5, 0xfc, 0x4f,
+ 0xda, 0xc7, 0xdb, 0x39, 0xc2, 0xf0, 0x2e, 0xbe,
+ 0xe4, 0xe3, 0x54, 0x1d, 0x1e, 0x78, 0x04, 0x7a,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, },
+ {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e,
+ 0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38,
+ 0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36,
+ 0xed, 0x15, 0xf7, 0x8d, 0x37, 0x17, 0x32, 0xe4,
+ 0xf4, 0x1b, 0xf4, 0xf7, 0x88, 0x30, 0x35, 0xe6,
+ 0xa7, 0x9f, 0xce, 0xdc, 0x0e, 0x19, 0x6e, 0xb0,
+ 0x7b, 0x48, 0x17, 0x16, 0x97, 0x51, 0x74, 0x63,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, },
+ {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb,
+ 0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38,
+ 0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7,
+ 0xbe, 0xe2, 0xc0, 0xfd, 0x39, 0xbb, 0x30, 0xea,
+ 0xb3, 0x37, 0xe0, 0xa5, 0x21, 0xb6, 0xcb, 0xa1,
+ 0xab, 0xe4, 0xb2, 0xb3, 0xa3, 0xe5, 0x24, 0xc1,
+ 0x4a, 0x3f, 0xe3, 0xeb, 0x11, 0x6b, 0x65, 0x5f,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0b, },
+ {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f,
+ 0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50,
+ 0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16,
+ 0x44, 0x8e, 0x50, 0x7c, 0x20, 0xb5, 0x10, 0x00,
+ 0x40, 0x92, 0xe9, 0x66, 0x36, 0xcf, 0xb7, 0xe3,
+ 0x2e, 0xfd, 0xed, 0x82, 0x65, 0xc2, 0x66, 0xdf,
+ 0xb7, 0x54, 0xfa, 0x6d, 0x64, 0x91, 0xa6, 0xda,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, },
+ {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b,
+ 0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43,
+ 0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3,
+ 0x04, 0x4f, 0x4f, 0x7a, 0x20, 0x7d, 0xdd, 0xf0,
+ 0x38, 0x5b, 0xfd, 0xea, 0xb6, 0xe9, 0xac, 0xda,
+ 0x8d, 0xa0, 0x6b, 0x3b, 0xbe, 0xf2, 0x24, 0xa9,
+ 0x3a, 0xb1, 0xe9, 0xe0, 0x36, 0x10, 0x9d, 0x13,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0d, },
+ {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28,
+ 0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42,
+ 0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98,
+ 0x1f, 0xcf, 0xae, 0xca, 0x25, 0x28, 0x19, 0xf7,
+ 0x1c, 0x7f, 0xb7, 0xfb, 0xcb, 0x15, 0x9b, 0xe3,
+ 0x37, 0xd3, 0x7d, 0x33, 0x36, 0xd7, 0xfe, 0xb9,
+ 0x63, 0x72, 0x4f, 0xdf, 0xb0, 0xec, 0xb7, 0x67,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0e, },
+ {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60,
+ 0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2,
+ 0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2,
+ 0xce, 0x01, 0xe9, 0xfa, 0xd5, 0x81, 0x4c, 0xd7,
+ 0x24, 0x19, 0x9c, 0x4a, 0x5b, 0x97, 0x4a, 0x43,
+ 0x68, 0x5f, 0xbf, 0x5b, 0x8b, 0xac, 0x69, 0x45,
+ 0x9c, 0x94, 0x69, 0xbc, 0x8f, 0x23, 0xcc, 0xaf,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0f, },
+ {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2,
+ 0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29,
+ 0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e,
+ 0x21, 0x91, 0x6b, 0xf9, 0x97, 0x9a, 0x5f, 0x47,
+ 0x59, 0xf8, 0x0f, 0x4f, 0xb4, 0xec, 0x2e, 0x34,
+ 0xf5, 0x56, 0x6d, 0x59, 0x56, 0x80, 0xa1, 0x17,
+ 0x35, 0xe7, 0xb6, 0x10, 0x46, 0x12, 0x79, 0x89,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, },
+ {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24,
+ 0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c,
+ 0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5,
+ 0x90, 0xc4, 0xc6, 0x6d, 0x33, 0x99, 0xd4, 0x64,
+ 0x34, 0x59, 0x06, 0xb1, 0x1b, 0x00, 0xe3, 0x63,
+ 0xef, 0x42, 0x92, 0x21, 0xf2, 0xec, 0x72, 0x0d,
+ 0x2f, 0x66, 0x5d, 0x7d, 0xea, 0xd5, 0xb4, 0x82,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x11, },
+ {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88,
+ 0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20,
+ 0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c,
+ 0x48, 0x44, 0x03, 0xbc, 0xff, 0x14, 0x9e, 0xfa,
+ 0x66, 0x06, 0xa6, 0xbd, 0x20, 0xef, 0x7d, 0x1b,
+ 0x06, 0xbd, 0x92, 0xf6, 0x90, 0x46, 0x39, 0xdc,
+ 0xe5, 0x17, 0x4d, 0xb6, 0xcc, 0x55, 0x4a, 0x26,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x12, },
+ {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05,
+ 0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea,
+ 0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74,
+ 0x62, 0x26, 0xe4, 0xcc, 0xea, 0x98, 0xd6, 0x0e,
+ 0x5f, 0xfc, 0x9b, 0x8f, 0xcf, 0x99, 0x9f, 0xab,
+ 0x1d, 0xf7, 0xe7, 0xef, 0x70, 0x84, 0xf2, 0x0d,
+ 0xdb, 0x61, 0xbb, 0x04, 0x5a, 0x6c, 0xe0, 0x02,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x13, },
+ {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01,
+ 0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc,
+ 0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb,
+ 0xc6, 0xca, 0xe8, 0x3c, 0xdc, 0xf1, 0xf6, 0xc3,
+ 0xdb, 0x09, 0xc7, 0x0a, 0xcc, 0x25, 0x39, 0x1d,
+ 0x49, 0x2f, 0xe2, 0x5b, 0x4a, 0x18, 0x0b, 0xab,
+ 0xd6, 0xce, 0xa3, 0x56, 0xc0, 0x47, 0x19, 0xcd,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, },
+ {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a,
+ 0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf,
+ 0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee,
+ 0xfe, 0x78, 0x24, 0x55, 0x0d, 0x5d, 0x71, 0x10,
+ 0x27, 0x4c, 0xba, 0x7c, 0xde, 0xe9, 0x0e, 0x1a,
+ 0x8b, 0x0d, 0x39, 0x4c, 0x37, 0x6a, 0x55, 0x73,
+ 0xdb, 0x6b, 0xe0, 0xbf, 0x27, 0x47, 0xf5, 0x30,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x8e, 0xbb, 0xb9,
+ 0x5e, 0xed, 0x0e, 0x13, },
+ {0x61, 0xf0, 0x77, 0xc6, 0xf6, 0x2e, 0xd8, 0x02,
+ 0xda, 0xd7, 0xc2, 0xf3, 0x8f, 0x5c, 0x67, 0xf2,
+ 0xcc, 0x45, 0x36, 0x01, 0xe6, 0x1b, 0xd0, 0x76,
+ 0xbb, 0x46, 0x17, 0x9e, 0x22, 0x72, 0xf9, 0xe9,
+ 0xf5, 0x93, 0x3e, 0x70, 0x38, 0x8e, 0xe6, 0x52,
+ 0x51, 0x34, 0x43, 0xb5, 0xe2, 0x89, 0xdd, 0x13,
+ 0x5d, 0xcc, 0x0d, 0x02, 0x99, 0xb2, 0x25, 0xe4,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x9d, 0x89,
+ 0x3d, 0x4c, 0xdd, 0x74, 0x72, 0x46, 0xcd, 0xca,
+ 0x43, 0x59, 0x0e, 0x13, },
+ {0x02, 0x98, 0x95, 0xf0, 0xaf, 0x49, 0x6b, 0xfc,
+ 0x62, 0xb6, 0xef, 0x8d, 0x8a, 0x65, 0xc8, 0x8c,
+ 0x61, 0x39, 0x49, 0xb0, 0x36, 0x68, 0xaa, 0xb4,
+ 0xf0, 0x42, 0x9e, 0x35, 0x3e, 0xa6, 0xe5, 0x3f,
+ 0x9a, 0x84, 0x1f, 0x20, 0x19, 0xec, 0x24, 0xbd,
+ 0xe1, 0xa7, 0x56, 0x77, 0xaa, 0x9b, 0x59, 0x02,
+ 0xe6, 0x10, 0x81, 0xc0, 0x10, 0x64, 0xde, 0x93,
+ },
+ },
+ {
+ {0x41, 0xff, 0xc1, 0xff, 0xff, 0xfe, 0x01, 0xff,
+ 0xfc, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x07, 0xc0,
+ 0x01, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xf0, 0x7f,
+ 0xfe, 0x00, 0x07, 0xc0, },
+ {0xab, 0x68, 0x99, 0x30, 0xbc, 0xae, 0x4a, 0x4a,
+ 0xa5, 0xf5, 0xcb, 0x08, 0x5e, 0x82, 0x3e, 0x8a,
+ 0xe3, 0x0f, 0xd3, 0x65, 0xeb, 0x1d, 0xa4, 0xab,
+ 0xa9, 0xcf, 0x03, 0x79, 0x33, 0x45, 0xa1, 0x21,
+ 0xbb, 0xd2, 0x33, 0x54, 0x8a, 0xf0, 0xd2, 0x10,
+ 0x65, 0x4e, 0xb4, 0x0b, 0xab, 0x78, 0x8a, 0x03,
+ 0x66, 0x64, 0x19, 0xbe, 0x6f, 0xbd, 0x34, 0xe7,
+ },
+ },
+ {
+ {0x7f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xc0, 0x03,
+ 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x0e, 0x00, 0xff, },
+ {0xbd, 0xb6, 0xa8, 0x81, 0x7c, 0x1f, 0x89, 0xda,
+ 0x1c, 0x2f, 0x3d, 0xd8, 0xe9, 0x7f, 0xeb, 0x44,
+ 0x94, 0xf2, 0xed, 0x30, 0x2a, 0x4c, 0xe2, 0xbc,
+ 0x7f, 0x5f, 0x40, 0x25, 0x4c, 0x70, 0x20, 0xd5,
+ 0x7c, 0x00, 0x41, 0x18, 0x89, 0x46, 0x2d, 0x77,
+ 0xa5, 0x43, 0x8b, 0xb4, 0xe9, 0x7d, 0x17, 0x77,
+ 0x00, 0xbf, 0x72, 0x43, 0xa0, 0x7f, 0x16, 0x80,
+ },
+ },
+ {
+ {0x7f, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff,
+ 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
+ 0x00, 0x0f, 0xff, 0xff, },
+ {0xd5, 0x8b, 0x61, 0xaa, 0x41, 0xc3, 0x2d, 0xd5,
+ 0xeb, 0xa4, 0x62, 0x64, 0x7d, 0xba, 0x75, 0xc5,
+ 0xd6, 0x7c, 0x83, 0x60, 0x6c, 0x0a, 0xf2, 0xbd,
+ 0x92, 0x84, 0x46, 0xa9, 0xd2, 0x4b, 0xa6, 0xa8,
+ 0x37, 0xbe, 0x04, 0x60, 0xdd, 0x10, 0x7a, 0xe7,
+ 0x77, 0x25, 0x69, 0x6d, 0x21, 0x14, 0x46, 0xc5,
+ 0x60, 0x9b, 0x45, 0x95, 0x97, 0x6b, 0x16, 0xbd,
+ },
+ },
+ {
+ {0x7f, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xfe, 0x3f,
+ 0xff, 0xfc, 0x10, 0x00, 0x00, 0x20, 0x00, 0x3f,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x3f, 0xff, 0xff, 0xff, },
+ {0xdc, 0x9f, 0xa7, 0x79, 0x78, 0xa0, 0x05, 0x51,
+ 0x09, 0x80, 0xe9, 0x29, 0xa1, 0x48, 0x5f, 0x63,
+ 0x71, 0x6d, 0xf6, 0x95, 0xd7, 0xa0, 0xc1, 0x8b,
+ 0xb5, 0x18, 0xdf, 0x03, 0xed, 0xe2, 0xb0, 0x16,
+ 0xf2, 0xdd, 0xff, 0xc2, 0xa8, 0xc0, 0x15, 0xb1,
+ 0x34, 0x92, 0x82, 0x75, 0xce, 0x09, 0xe5, 0x66,
+ 0x1b, 0x7a, 0xb1, 0x4c, 0xe0, 0xd1, 0xd4, 0x03,
+ },
+ },
+ {
+ {0x70, 0x01, 0xf0, 0x00, 0x1c, 0x00, 0x01, 0xc0,
+ 0x00, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x00, 0x00,
+ 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xc0, 0x00,
+ 0x00, 0x01, 0xfc, 0x00, },
+ {0x49, 0x9d, 0x8b, 0x28, 0x29, 0xcf, 0xb8, 0x79,
+ 0xc9, 0x01, 0xf7, 0xd8, 0x5d, 0x35, 0x70, 0x45,
+ 0xed, 0xab, 0x55, 0x02, 0x88, 0x24, 0xd0, 0xf0,
+ 0x5b, 0xa2, 0x79, 0xba, 0xbf, 0x92, 0x95, 0x37,
+ 0xb0, 0x6e, 0x40, 0x15, 0x91, 0x96, 0x39, 0xd9,
+ 0x4f, 0x57, 0x83, 0x8f, 0xa3, 0x3f, 0xc3, 0xd9,
+ 0x52, 0x59, 0x8d, 0xcd, 0xbb, 0x44, 0xd6, 0x38,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00,
+ 0x00, 0xff, 0xf0, 0x30, 0x00, 0x1f, 0x00, 0x00,
+ 0xff, 0xff, 0xf0, 0x00, 0x00, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, },
+ {0x82, 0x46, 0xc9, 0x99, 0x13, 0x71, 0x86, 0x63,
+ 0x2c, 0x5f, 0x9e, 0xdd, 0xf3, 0xb1, 0xb0, 0xe1,
+ 0x76, 0x4c, 0x5e, 0x8b, 0xd0, 0xe0, 0xd8, 0xa5,
+ 0x54, 0xb9, 0xcb, 0x77, 0xe8, 0x0e, 0xd8, 0x66,
+ 0x0b, 0xc1, 0xcb, 0x17, 0xac, 0x7d, 0x84, 0x5b,
+ 0xe4, 0x0a, 0x7a, 0x02, 0x2d, 0x33, 0x06, 0xf1,
+ 0x16, 0xae, 0x9f, 0x81, 0xfe, 0xa6, 0x59, 0x47,
+ },
+ },
+ {
+ {0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xfe, 0x08, 0x00, 0x00, 0x1f,
+ 0xf0, 0x00, 0x1f, 0xff, },
+ {0x66, 0x70, 0xc2, 0x0a, 0xfc, 0xce, 0xae, 0xa6,
+ 0x72, 0xc9, 0x7f, 0x75, 0xe2, 0xe9, 0xdd, 0x5c,
+ 0x84, 0x60, 0xe5, 0x4b, 0xb3, 0x85, 0x38, 0xeb,
+ 0xb4, 0xbd, 0x30, 0xeb, 0xf2, 0x80, 0xd8, 0x00,
+ 0x8d, 0x07, 0xa4, 0xca, 0xf5, 0x42, 0x71, 0xf9,
+ 0x93, 0x52, 0x7d, 0x46, 0xff, 0x3f, 0xf4, 0x6f,
+ 0xd1, 0x19, 0x0a, 0x3f, 0x1f, 0xaa, 0x4f, 0x74,
+ },
+ },
+ {
+ {0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xe0, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, },
+ {0x00, 0x0e, 0xca, 0x93, 0x42, 0x47, 0x42, 0x5c,
+ 0xfd, 0x94, 0x9b, 0x79, 0x5c, 0xb5, 0xce, 0x1e,
+ 0xff, 0x40, 0x15, 0x50, 0x38, 0x6e, 0x28, 0xd1,
+ 0xa4, 0xc5, 0xa8, 0xeb, 0xd4, 0xc0, 0x10, 0x40,
+ 0xdb, 0xa1, 0x96, 0x28, 0x93, 0x1b, 0xc8, 0x85,
+ 0x53, 0x70, 0x31, 0x7c, 0x72, 0x2c, 0xbd, 0x9c,
+ 0xa6, 0x15, 0x69, 0x85, 0xf1, 0xc2, 0xe9, 0xce,
+ },
+ },
+ {
+ {0x7f, 0xff, 0xfc, 0x03, 0xff, 0x80, 0x7f, 0xff,
+ 0xe0, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x0f, 0xff,
+ 0x80, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff,
+ 0xff, 0xfe, 0x00, 0x1f, },
+ {0xef, 0x35, 0x3b, 0xf5, 0xc7, 0x3c, 0xd5, 0x51,
+ 0xb9, 0x6d, 0x59, 0x6f, 0xbc, 0x9a, 0x67, 0xf1,
+ 0x6d, 0x61, 0xdd, 0x9f, 0xe5, 0x6a, 0xf1, 0x9d,
+ 0xe1, 0xfb, 0xa9, 0xcd, 0x21, 0x77, 0x1b, 0x9c,
+ 0xdc, 0xe3, 0xe8, 0x43, 0x0c, 0x09, 0xb3, 0x83,
+ 0x8b, 0xe7, 0x0b, 0x48, 0xc2, 0x1e, 0x15, 0xbc,
+ 0x09, 0xee, 0x1f, 0x2d, 0x79, 0x45, 0xb9, 0x1f,
+ },
+ },
+ {
+ {0x00, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x7f, 0xff,
+ 0xff, 0xff, 0x01, 0xff, 0xfe, 0x03, 0xff, 0xfe,
+ 0x40, 0x00, 0x38, 0x00, 0x07, 0xe0, 0x00, 0x3f,
+ 0xfe, 0x00, 0x00, 0x00, },
+ {0x40, 0x36, 0x05, 0x2a, 0x30, 0x91, 0xeb, 0x48,
+ 0x10, 0x46, 0xad, 0x32, 0x89, 0xc9, 0x5d, 0x3a,
+ 0xc9, 0x05, 0xca, 0x00, 0x23, 0xde, 0x2c, 0x03,
+ 0xec, 0xd4, 0x51, 0xcf, 0xd7, 0x68, 0x16, 0x5a,
+ 0x38, 0xa2, 0xb9, 0x6f, 0x81, 0x25, 0x86, 0xa9,
+ 0xd5, 0x9d, 0x41, 0x36, 0x03, 0x5d, 0x9c, 0x85,
+ 0x3a, 0x5b, 0xf2, 0xe1, 0xc8, 0x6a, 0x49, 0x93,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x29, },
+ {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a,
+ 0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf,
+ 0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee,
+ 0xfe, 0x78, 0x24, 0x55, 0xf2, 0xa2, 0x8e, 0xef,
+ 0xd8, 0xb3, 0x45, 0x83, 0x21, 0x16, 0xf1, 0xe5,
+ 0x74, 0xf2, 0xc6, 0xb2, 0xc8, 0x95, 0xaa, 0x8c,
+ 0x24, 0x94, 0x1f, 0x40, 0xd8, 0xb8, 0x0a, 0xd1,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x2a, },
+ {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01,
+ 0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc,
+ 0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb,
+ 0xc6, 0xca, 0xe8, 0x3c, 0x23, 0x0e, 0x09, 0x3c,
+ 0x24, 0xf6, 0x38, 0xf5, 0x33, 0xda, 0xc6, 0xe2,
+ 0xb6, 0xd0, 0x1d, 0xa3, 0xb5, 0xe7, 0xf4, 0x54,
+ 0x29, 0x31, 0x5c, 0xa9, 0x3f, 0xb8, 0xe6, 0x34,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x2b, },
+ {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05,
+ 0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea,
+ 0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74,
+ 0x62, 0x26, 0xe4, 0xcc, 0x15, 0x67, 0x29, 0xf1,
+ 0xa0, 0x03, 0x64, 0x70, 0x30, 0x66, 0x60, 0x54,
+ 0xe2, 0x08, 0x18, 0x0f, 0x8f, 0x7b, 0x0d, 0xf2,
+ 0x24, 0x9e, 0x44, 0xfb, 0xa5, 0x93, 0x1f, 0xff,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x2c, },
+ {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88,
+ 0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20,
+ 0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c,
+ 0x48, 0x44, 0x03, 0xbc, 0x00, 0xeb, 0x61, 0x05,
+ 0x99, 0xf9, 0x59, 0x42, 0xdf, 0x10, 0x82, 0xe4,
+ 0xf9, 0x42, 0x6d, 0x08, 0x6f, 0xb9, 0xc6, 0x23,
+ 0x1a, 0xe8, 0xb2, 0x49, 0x33, 0xaa, 0xb5, 0xdb,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x2d, },
+ {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24,
+ 0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c,
+ 0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5,
+ 0x90, 0xc4, 0xc6, 0x6d, 0xcc, 0x66, 0x2b, 0x9b,
+ 0xcb, 0xa6, 0xf9, 0x4e, 0xe4, 0xff, 0x1c, 0x9c,
+ 0x10, 0xbd, 0x6d, 0xdd, 0x0d, 0x13, 0x8d, 0xf2,
+ 0xd0, 0x99, 0xa2, 0x82, 0x15, 0x2a, 0x4b, 0x7f,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x2e, },
+ {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2,
+ 0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29,
+ 0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e,
+ 0x21, 0x91, 0x6b, 0xf9, 0x68, 0x65, 0xa0, 0xb8,
+ 0xa6, 0x07, 0xf0, 0xb0, 0x4b, 0x13, 0xd1, 0xcb,
+ 0x0a, 0xa9, 0x92, 0xa5, 0xa9, 0x7f, 0x5e, 0xe8,
+ 0xca, 0x18, 0x49, 0xef, 0xb9, 0xed, 0x86, 0x78,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x2f, },
+ {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60,
+ 0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2,
+ 0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2,
+ 0xce, 0x01, 0xe9, 0xfa, 0x2a, 0x7e, 0xb3, 0x28,
+ 0xdb, 0xe6, 0x63, 0xb5, 0xa4, 0x68, 0xb5, 0xbc,
+ 0x97, 0xa0, 0x40, 0xa3, 0x74, 0x53, 0x96, 0xba,
+ 0x63, 0x6b, 0x96, 0x43, 0x70, 0xdc, 0x33, 0x52,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x30, },
+ {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28,
+ 0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42,
+ 0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98,
+ 0x1f, 0xcf, 0xae, 0xca, 0xda, 0xd7, 0xe6, 0x08,
+ 0xe3, 0x80, 0x48, 0x04, 0x34, 0xea, 0x64, 0x1c,
+ 0xc8, 0x2c, 0x82, 0xcb, 0xc9, 0x28, 0x01, 0x46,
+ 0x9c, 0x8d, 0xb0, 0x20, 0x4f, 0x13, 0x48, 0x9a,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x31, },
+ {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b,
+ 0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43,
+ 0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3,
+ 0x04, 0x4f, 0x4f, 0x7a, 0xdf, 0x82, 0x22, 0x0f,
+ 0xc7, 0xa4, 0x02, 0x15, 0x49, 0x16, 0x53, 0x25,
+ 0x72, 0x5f, 0x94, 0xc3, 0x41, 0x0d, 0xdb, 0x56,
+ 0xc5, 0x4e, 0x16, 0x1f, 0xc9, 0xef, 0x62, 0xee,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x32, },
+ {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f,
+ 0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50,
+ 0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16,
+ 0x44, 0x8e, 0x50, 0x7c, 0xdf, 0x4a, 0xef, 0xff,
+ 0xbf, 0x6d, 0x16, 0x99, 0xc9, 0x30, 0x48, 0x1c,
+ 0xd1, 0x02, 0x12, 0x7c, 0x9a, 0x3d, 0x99, 0x20,
+ 0x48, 0xab, 0x05, 0x92, 0x9b, 0x6e, 0x59, 0x27,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x33, },
+ {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb,
+ 0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38,
+ 0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7,
+ 0xbe, 0xe2, 0xc0, 0xfd, 0xc6, 0x44, 0xcf, 0x15,
+ 0x4c, 0xc8, 0x1f, 0x5a, 0xde, 0x49, 0x34, 0x5e,
+ 0x54, 0x1b, 0x4d, 0x4b, 0x5c, 0x1a, 0xdb, 0x3e,
+ 0xb5, 0xc0, 0x1c, 0x14, 0xee, 0x94, 0x9a, 0xa2,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x34, },
+ {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e,
+ 0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38,
+ 0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36,
+ 0xed, 0x15, 0xf7, 0x8d, 0xc8, 0xe8, 0xcd, 0x1b,
+ 0x0b, 0xe4, 0x0b, 0x08, 0x77, 0xcf, 0xca, 0x19,
+ 0x58, 0x60, 0x31, 0x22, 0xf1, 0xe6, 0x91, 0x4f,
+ 0x84, 0xb7, 0xe8, 0xe9, 0x68, 0xae, 0x8b, 0x9e,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x35, },
+ {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31,
+ 0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0,
+ 0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b,
+ 0x55, 0x57, 0x15, 0x50, 0xfb, 0x92, 0x32, 0xc1,
+ 0x5a, 0x3b, 0xc7, 0x67, 0x3a, 0x3a, 0x03, 0xb0,
+ 0x25, 0x38, 0x24, 0xc5, 0x3d, 0x0f, 0xd1, 0x41,
+ 0x1b, 0x1c, 0xab, 0xe2, 0xe1, 0x87, 0xfb, 0x87,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x36, },
+ {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5,
+ 0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23,
+ 0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24,
+ 0xa0, 0x3c, 0x3e, 0x28, 0xf0, 0xc5, 0xcf, 0xf7,
+ 0xab, 0x68, 0x0d, 0x09, 0xee, 0x11, 0xda, 0xe8,
+ 0x4e, 0x9c, 0x10, 0x72, 0xac, 0x48, 0xea, 0x2e,
+ 0x74, 0x4b, 0x1b, 0x7f, 0x72, 0xfd, 0x46, 0x9e,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x37, },
+ {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f,
+ 0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d,
+ 0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c,
+ 0x57, 0x11, 0x24, 0x08, 0x76, 0x05, 0x0f, 0x33,
+ 0x48, 0xaf, 0x26, 0x64, 0xaa, 0xc3, 0xa8, 0xb0,
+ 0x52, 0x81, 0x30, 0x4e, 0xbc, 0x7a, 0x79, 0x14,
+ 0xc6, 0xad, 0x50, 0xa4, 0xb4, 0xea, 0xc3, 0x83,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x38, },
+ {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07,
+ 0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90,
+ 0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75,
+ 0x26, 0xf0, 0x11, 0xaa, 0xd8, 0x17, 0x40, 0x0e,
+ 0x8b, 0xa9, 0xca, 0x13, 0xa4, 0x5f, 0x36, 0x0e,
+ 0x3d, 0x12, 0x1e, 0xaa, 0xeb, 0x39, 0xaf, 0x82,
+ 0xd6, 0x00, 0x1c, 0x81, 0x86, 0xf5, 0xf8, 0x66,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x39, },
+ {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45,
+ 0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02,
+ 0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e,
+ 0x40, 0x44, 0x73, 0x01, 0xfb, 0x7d, 0xa7, 0xf5,
+ 0xf1, 0x3a, 0x43, 0xb8, 0x17, 0x74, 0x37, 0x3c,
+ 0x87, 0x9c, 0xd3, 0x2d, 0x69, 0x34, 0xc0, 0x5f,
+ 0xa7, 0x58, 0xee, 0xb1, 0x4f, 0xcf, 0xab, 0x38,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x3a, },
+ {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3,
+ 0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc,
+ 0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08,
+ 0xfd, 0x89, 0x6d, 0x04, 0x5c, 0x08, 0x0f, 0xc3,
+ 0x52, 0x2f, 0x41, 0xbb, 0xb3, 0xf5, 0x5a, 0x97,
+ 0xcf, 0xec, 0xf2, 0x1f, 0x88, 0x2c, 0xe8, 0xcb,
+ 0xb1, 0xe5, 0x0c, 0xa6, 0xe6, 0x7e, 0x56, 0xdc,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x3b, },
+ {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67,
+ 0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88,
+ 0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd,
+ 0x1a, 0x70, 0x4f, 0xa6, 0xe3, 0xd4, 0x89, 0x58,
+ 0x43, 0xda, 0x18, 0x8f, 0xd5, 0x8f, 0xb0, 0x56,
+ 0x79, 0x76, 0xd7, 0xb5, 0x03, 0x59, 0xd6, 0xb7,
+ 0x85, 0x30, 0xc8, 0xf6, 0x2d, 0x1b, 0x17, 0x46,
+ },
+ },
+ {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+ 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+ 0x5c, 0x5c, 0x2a, 0x3c, },
+ {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
+ 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
+ 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
+ 0x11, 0x5c, 0x1d, 0x21, 0x42, 0xc8, 0x9c, 0x77,
+ 0x4a, 0x08, 0xdc, 0x04, 0xb3, 0xdd, 0x20, 0x19,
+ 0x32, 0xbc, 0x8a, 0x5e, 0xa5, 0xf8, 0xb8, 0x9b,
+ 0xbb, 0x2a, 0x7e, 0x66, 0x7a, 0xff, 0x81, 0xcd,
+ },
+ },
+};
+
+TEST(P224, ExternalToInternalAndBack) {
+ Point point;
+
+ EXPECT_TRUE(point.SetFromString(base::StringPiece(
+ reinterpret_cast<const char *>(kBasePointExternal),
+ sizeof(kBasePointExternal))));
+
+ const std::string external = point.ToString();
+
+ ASSERT_EQ(external.size(), 56u);
+ EXPECT_TRUE(memcmp(external.data(), kBasePointExternal,
+ sizeof(kBasePointExternal)) == 0);
+}
+
+TEST(P224, ScalarBaseMult) {
+ Point point;
+
+ for (size_t i = 0; i < arraysize(kNISTTestVectors); i++) {
+ p224::ScalarBaseMult(kNISTTestVectors[i].scalar, &point);
+ const std::string external = point.ToString();
+ ASSERT_EQ(external.size(), 56u);
+ EXPECT_TRUE(memcmp(external.data(), kNISTTestVectors[i].affine,
+ external.size()) == 0);
+ }
+}
+
+TEST(P224, Addition) {
+ Point a, b, minus_b, sum, a_again;
+
+ ASSERT_TRUE(a.SetFromString(base::StringPiece(
+ reinterpret_cast<const char *>(kNISTTestVectors[10].affine), 56)));
+ ASSERT_TRUE(b.SetFromString(base::StringPiece(
+ reinterpret_cast<const char *>(kNISTTestVectors[11].affine), 56)));
+
+ p224::Negate(b, &minus_b);
+ p224::Add(a, b, &sum);
+ EXPECT_TRUE(memcmp(&sum, &a, sizeof(sum)) != 0);
+ p224::Add(minus_b, sum, &a_again);
+ EXPECT_TRUE(a_again.ToString() == a.ToString());
+}
+
+TEST(P224, Infinity) {
+ char zeros[56];
+ memset(zeros, 0, sizeof(zeros));
+
+ // Test that x^0 = ∞.
+ Point a;
+ p224::ScalarBaseMult(reinterpret_cast<const uint8_t*>(zeros), &a);
+ EXPECT_TRUE(memcmp(zeros, a.ToString().data(), sizeof(zeros)) == 0);
+
+ // We shouldn't allow ∞ to be imported.
+ EXPECT_FALSE(a.SetFromString(std::string(zeros, sizeof(zeros))));
+}
+
+} // namespace crypto
diff --git a/crypto/random.cc b/crypto/random.cc
new file mode 100644
index 0000000..847d5df
--- /dev/null
+++ b/crypto/random.cc
@@ -0,0 +1,28 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/random.h"
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/rand_util.h"
+
+namespace crypto {
+
+void RandBytes(base::span<uint8_t> bytes) {
+ // base::RandBytes() is already strongly random, so this is just an alias for
+ // it. If base needs a non-strong RNG function in the future, it will get a
+ // different name.
+ base::RandBytes(bytes);
+}
+
+std::vector<uint8_t> RandBytesAsVector(size_t length) {
+ std::vector<uint8_t> result(length);
+ RandBytes(result);
+ return result;
+}
+
+} // namespace crypto
diff --git a/crypto/random.h b/crypto/random.h
new file mode 100644
index 0000000..a8a4056
--- /dev/null
+++ b/crypto/random.h
@@ -0,0 +1,25 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_RANDOM_H_
+#define CRYPTO_RANDOM_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/containers/span.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Fills `bytes` with cryptographically-secure random bits.
+CRYPTO_EXPORT void RandBytes(base::span<uint8_t> bytes);
+
+// Returns a vector of `length` bytes filled with cryptographically-secure
+// random bits.
+CRYPTO_EXPORT std::vector<uint8_t> RandBytesAsVector(size_t length);
+}
+
+#endif // CRYPTO_RANDOM_H_
diff --git a/crypto/random_unittest.cc b/crypto/random_unittest.cc
new file mode 100644
index 0000000..ec93b90
--- /dev/null
+++ b/crypto/random_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/random.h"
+
+#include <stddef.h>
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Basic functionality tests. Does NOT test the security of the random data.
+
+// Ensures we don't have all trivial data, i.e. that the data is indeed random.
+// Currently, that means the bytes cannot be all the same (e.g. all zeros).
+bool IsTrivial(base::span<const uint8_t> bytes) {
+ for (size_t i = 0u; i < bytes.size(); i++) {
+ if (bytes[i] != bytes[0]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+TEST(RandBytes, RandBytes) {
+ std::array<uint8_t, 16> bytes;
+ crypto::RandBytes(bytes);
+ EXPECT_FALSE(IsTrivial(bytes));
+}
+
+TEST(RandBytes, RandBytesAsVector) {
+ std::vector<uint8_t> vector = crypto::RandBytesAsVector(16);
+ EXPECT_FALSE(IsTrivial(vector));
+}
diff --git a/crypto/rsa_private_key.cc b/crypto/rsa_private_key.cc
new file mode 100644
index 0000000..08418f7
--- /dev/null
+++ b/crypto/rsa_private_key.cc
@@ -0,0 +1,387 @@
+// Copyright 2011 The Chromium Authors
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/strings/string_util.h"
+
+// This file manually encodes and decodes RSA private keys using PrivateKeyInfo
+// from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are:
+//
+// PrivateKeyInfo ::= SEQUENCE {
+// version Version,
+// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+// privateKey PrivateKey,
+// attributes [0] IMPLICIT Attributes OPTIONAL
+// }
+//
+// RSAPrivateKey ::= SEQUENCE {
+// version Version,
+// modulus INTEGER,
+// publicExponent INTEGER,
+// privateExponent INTEGER,
+// prime1 INTEGER,
+// prime2 INTEGER,
+// exponent1 INTEGER,
+// exponent2 INTEGER,
+// coefficient INTEGER
+// }
+
+namespace {
+// Helper for error handling during key import.
+#define READ_ASSERT(truth) \
+ if (!(truth)) { \
+ NOTREACHED(); \
+ return false; \
+ }
+} // namespace
+
+namespace crypto {
+
+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();
+ if (out->size() == expected_size + 1) {
+ READ_ASSERT(out->front() == 0x00);
+ pad++;
+ } 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 crypto
diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h
new file mode 100644
index 0000000..7ffb412
--- /dev/null
+++ b/crypto/rsa_private_key.h
@@ -0,0 +1,224 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_RSA_PRIVATE_KEY_H_
+#define CRYPTO_RSA_PRIVATE_KEY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <list>
+#include <vector>
+
+#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 {
+
+// 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 kNullTag = 0x05;
+ 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(const PrivateKeyInfoCodec&) = delete;
+ PrivateKeyInfoCodec& operator=(const PrivateKeyInfoCodec&) = delete;
+
+ ~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_;
+};
+
+// Encapsulates an RSA private key. Can be used to generate new keys, export
+// keys to other formats, or to extract a public key.
+// TODO(hclam): This class should be ref-counted so it can be reused easily.
+class CRYPTO_EXPORT RSAPrivateKey {
+ public:
+ RSAPrivateKey(const RSAPrivateKey&) = delete;
+ RSAPrivateKey& operator=(const RSAPrivateKey&) = delete;
+ ~RSAPrivateKey();
+
+ // Create a new random instance. Can return NULL if initialization fails.
+ static RSAPrivateKey* Create(uint16_t num_bits);
+
+ // Create a new instance by importing an existing private key. The format is
+ // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if
+ // initialization fails.
+ 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;
+
+ // Exports the private key to a PKCS #8 PrivateKeyInfo block.
+ bool ExportPrivateKey(std::vector<uint8_t>* output) const;
+
+ // Exports the public key to an X509 SubjectPublicKeyInfo block.
+ bool ExportPublicKey(std::vector<uint8_t>* output) const;
+
+ private:
+ // 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
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_RSA_PRIVATE_KEY_H_
diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc
new file mode 100644
index 0000000..116952f
--- /dev/null
+++ b/crypto/rsa_private_key_nss.cc
@@ -0,0 +1,151 @@
+// Copyright 2011 The Chromium Authors
+// 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/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"
+
+// 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;
+}
+
+} // 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/rsa_private_key_unittest.cc b/crypto/rsa_private_key_unittest.cc
new file mode 100644
index 0000000..db65133
--- /dev/null
+++ b/crypto/rsa_private_key_unittest.cc
@@ -0,0 +1,380 @@
+// Copyright 2011 The Chromium Authors
+// 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 <stdint.h>
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const uint8_t kTestPrivateKeyInfo[] = {
+ 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+ 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+ 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61,
+ 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 0x55, 0x84, 0xd5, 0x3a,
+ 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4,
+ 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 0xb0, 0x40, 0x53, 0x3a,
+ 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f,
+ 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 0xde, 0x4e, 0xb9, 0x57,
+ 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff,
+ 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 0x84, 0x32, 0x33, 0xf3,
+ 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5,
+ 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 0x53, 0x56, 0xa6, 0x83,
+ 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, 0x37, 0xcb, 0xf2, 0x98,
+ 0xa0, 0xce, 0xb4, 0xcb, 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7,
+ 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, 0xed, 0xb8, 0x48, 0x8b,
+ 0x16, 0x93, 0x36, 0x95, 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6,
+ 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, 0x43, 0x78, 0xf9, 0xfe,
+ 0x1f, 0x33, 0x23, 0x1e, 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b,
+ 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, 0x86, 0xb2, 0xcb, 0x3c,
+ 0xfe, 0x4e, 0xa1, 0xfa, 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38,
+ 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, 0xa3, 0xf6, 0x85, 0x6b,
+ 0x84, 0x43, 0xc9, 0x1e, 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e,
+ 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, 0x29, 0x5c, 0xc0, 0x4f,
+ 0x01, 0x02, 0x41, 0x00, 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c,
+ 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, 0xcc, 0x61, 0xcd, 0x38,
+ 0x42, 0x20, 0xd3, 0x82, 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89,
+ 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, 0xba, 0x16, 0x1a, 0xea,
+ 0x15, 0xc6, 0xf0, 0xb8, 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2,
+ 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, 0x02, 0x41, 0x00, 0xc0,
+ 0x60, 0x62, 0x80, 0xe1, 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72,
+ 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, 0x7d, 0xd6, 0xb8, 0x31,
+ 0x2b, 0x84, 0x7f, 0x62, 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c,
+ 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, 0x5c, 0x09, 0x3c, 0xcf,
+ 0x2f, 0x44, 0x9d, 0xb6, 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b,
+ 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, 0xe2, 0x0e, 0x56, 0xca,
+ 0x03, 0x1a, 0xc0, 0xf9, 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda,
+ 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, 0xda, 0x55, 0x98, 0x74,
+ 0xfc, 0x28, 0x17, 0x93, 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae,
+ 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, 0xb8, 0x06, 0x03, 0xba,
+ 0x08, 0x59, 0x2b, 0x17, 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41,
+ 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, 0xa0, 0x24, 0xf5, 0xdb,
+ 0x2f, 0xf0, 0x2f, 0xf1, 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0,
+ 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, 0xb4, 0x14, 0xd4, 0x09,
+ 0x91, 0x33, 0x5a, 0xfd, 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69,
+ 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, 0xff, 0x6e, 0xeb, 0xc6,
+ 0x86, 0xf5, 0xb4, 0xc7, 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f,
+ 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, 0x3e, 0x70, 0x8a, 0xbf,
+ 0x27, 0x49, 0xb0, 0x99, 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6,
+ 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, 0xc6, 0xa4, 0x92, 0xd1,
+ 0xce, 0x6c, 0x72, 0xfb, 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca,
+ 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, 0xb1, 0xc5, 0x15, 0xf3};
+
+} // namespace
+
+// Generate random private keys with two different sizes. Reimport, then
+// export them again. We should get back the same exact bytes.
+TEST(RSAPrivateKeyUnitTest, InitRandomTest) {
+ std::unique_ptr<crypto::RSAPrivateKey> keypair1(
+ crypto::RSAPrivateKey::Create(1024));
+ std::unique_ptr<crypto::RSAPrivateKey> keypair2(
+ crypto::RSAPrivateKey::Create(2048));
+ ASSERT_TRUE(keypair1.get());
+ ASSERT_TRUE(keypair2.get());
+
+ std::vector<uint8_t> privkey1;
+ std::vector<uint8_t> privkey2;
+ std::vector<uint8_t> pubkey1;
+ std::vector<uint8_t> pubkey2;
+
+ ASSERT_TRUE(keypair1->ExportPrivateKey(&privkey1));
+ ASSERT_TRUE(keypair2->ExportPrivateKey(&privkey2));
+ ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1));
+ ASSERT_TRUE(keypair2->ExportPublicKey(&pubkey2));
+
+ std::unique_ptr<crypto::RSAPrivateKey> keypair3(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey1));
+ std::unique_ptr<crypto::RSAPrivateKey> keypair4(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey2));
+ ASSERT_TRUE(keypair3.get());
+ ASSERT_TRUE(keypair4.get());
+
+ std::vector<uint8_t> privkey3;
+ std::vector<uint8_t> privkey4;
+ ASSERT_TRUE(keypair3->ExportPrivateKey(&privkey3));
+ ASSERT_TRUE(keypair4->ExportPrivateKey(&privkey4));
+
+ ASSERT_EQ(privkey1.size(), privkey3.size());
+ ASSERT_EQ(privkey2.size(), privkey4.size());
+ ASSERT_TRUE(0 == memcmp(&privkey1.front(), &privkey3.front(),
+ privkey1.size()));
+ ASSERT_TRUE(0 == memcmp(&privkey2.front(), &privkey4.front(),
+ privkey2.size()));
+}
+
+// Test Copy() method.
+TEST(RSAPrivateKeyUnitTest, CopyTest) {
+ std::vector<uint8_t> input(kTestPrivateKeyInfo,
+ kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
+
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+
+ std::unique_ptr<crypto::RSAPrivateKey> key_copy(key->Copy());
+ ASSERT_TRUE(key_copy.get());
+
+ std::vector<uint8_t> privkey_copy;
+ ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy));
+ ASSERT_EQ(input, privkey_copy);
+}
+
+// Test that CreateFromPrivateKeyInfo fails if there is extra data after the RSA
+// key.
+TEST(RSAPrivateKeyUnitTest, ExtraData) {
+ std::vector<uint8_t> input(kTestPrivateKeyInfo,
+ kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
+ input.push_back(0);
+
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+
+ // Import should fail.
+ EXPECT_FALSE(key);
+}
+
+TEST(RSAPrivateKeyUnitTest, NotRsaKey) {
+ // Defines a valid P-256 private key.
+ const uint8_t kTestEcPrivateKeyInfo[] = {
+ 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86,
+ 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+ 0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02, 0x01, 0x01, 0x04, 0x20,
+ 0x1F, 0xE3, 0x39, 0x50, 0xC5, 0xF4, 0x61, 0x12, 0x4A, 0xE9, 0x92, 0xC2,
+ 0xBD, 0xFD, 0xF1, 0xC7, 0x3B, 0x16, 0x15, 0xF5, 0x71, 0xBD, 0x56, 0x7E,
+ 0x60, 0xD1, 0x9A, 0xA1, 0xF4, 0x8C, 0xDF, 0x42, 0xA1, 0x44, 0x03, 0x42,
+ 0x00, 0x04, 0x7C, 0x11, 0x0C, 0x66, 0xDC, 0xFD, 0xA8, 0x07, 0xF6, 0xE6,
+ 0x9E, 0x45, 0xDD, 0xB3, 0xC7, 0x4F, 0x69, 0xA1, 0x48, 0x4D, 0x20, 0x3E,
+ 0x8D, 0xC5, 0xAD, 0xA8, 0xE9, 0xA9, 0xDD, 0x7C, 0xB3, 0xC7, 0x0D, 0xF4,
+ 0x48, 0x98, 0x6E, 0x51, 0xBD, 0xE5, 0xD1, 0x57, 0x6F, 0x99, 0x90, 0x1F,
+ 0x9C, 0x2C, 0x6A, 0x80, 0x6A, 0x47, 0xFD, 0x90, 0x76, 0x43, 0xA7, 0x2B,
+ 0x83, 0x55, 0x97, 0xEF, 0xC8, 0xC6};
+
+ std::vector<uint8_t> input(
+ kTestEcPrivateKeyInfo,
+ kTestEcPrivateKeyInfo + sizeof(kTestEcPrivateKeyInfo));
+
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+
+ // Import should fail as the given PKCS8 bytes were for an EC key not RSA key.
+ EXPECT_FALSE(key);
+}
+
+// Verify that generated public keys look good. This test data was generated
+// with the openssl command line tool.
+TEST(RSAPrivateKeyUnitTest, PublicKeyTest) {
+ const uint8_t expected_public_key_info[] = {
+ 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+ 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b,
+ 0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08,
+ 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04,
+ 0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a,
+ 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30,
+ 0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17,
+ 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89,
+ 0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85,
+ 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14,
+ 0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18,
+ 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6,
+ 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01};
+
+ std::vector<uint8_t> input(kTestPrivateKeyInfo,
+ kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
+
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+ ASSERT_TRUE(key.get());
+
+ std::vector<uint8_t> output;
+ ASSERT_TRUE(key->ExportPublicKey(&output));
+
+ ASSERT_TRUE(
+ memcmp(expected_public_key_info, &output.front(), output.size()) == 0);
+}
+
+// These two test keys each contain an integer that has 0x00 for its most
+// significant byte. When encoded as ASN.1, this byte is dropped and there are
+// two interesting sub-cases. When the sign bit of the integer is set, an extra
+// null byte is added back to force the encoded value to be positive. When the
+// sign bit is not set, the encoded integer is just left shorter than usual.
+// See also: http://code.google.com/p/chromium/issues/detail?id=14877.
+//
+// Before we were handling this correctly, we would see one of two failures:
+// * RSAPrivateKey::CreateFromPrivateKeyInfo would return null because the
+// underlying windows API failed to import the key.
+// * The import would succeed, but incorrectly interpret the data. On export,
+// the key would contain different values.
+//
+// This test case verifies these two failures modes don't occur.
+TEST(RSAPrivateKeyUnitTest, ShortIntegers) {
+ const uint8_t short_integer_with_high_bit[] = {
+ 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+ 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+ 0x00, 0x92, 0x59, 0x32, 0x7d, 0x8e, 0xaf, 0x2e, 0xd5, 0xb2, 0x5c, 0x67,
+ 0xc8, 0x7d, 0x48, 0xb7, 0x84, 0x12, 0xd0, 0x76, 0xda, 0xe1, 0xa3, 0x1e,
+ 0x40, 0x01, 0x14, 0x5c, 0xef, 0x26, 0x6e, 0x28, 0xa2, 0xf7, 0xa5, 0xb4,
+ 0x02, 0x37, 0xd0, 0x53, 0x10, 0xcb, 0x7c, 0x6a, 0xf4, 0x53, 0x9f, 0xb8,
+ 0xe0, 0x83, 0x93, 0xd1, 0x19, 0xd8, 0x28, 0xd1, 0xd1, 0xd8, 0x87, 0x8f,
+ 0x92, 0xfd, 0x73, 0xc0, 0x4d, 0x3e, 0x07, 0x22, 0x1f, 0xc1, 0x20, 0xb0,
+ 0x70, 0xb2, 0x3b, 0xea, 0xb1, 0xe5, 0x0a, 0xfd, 0x56, 0x49, 0x5e, 0x39,
+ 0x90, 0x91, 0xce, 0x04, 0x83, 0x29, 0xaa, 0xfd, 0x12, 0xa4, 0x42, 0x26,
+ 0x6c, 0x6e, 0x79, 0x70, 0x77, 0x03, 0xb2, 0x07, 0x01, 0x3d, 0x85, 0x81,
+ 0x95, 0x9e, 0xda, 0x5a, 0xa3, 0xf4, 0x2d, 0x38, 0x04, 0x58, 0xf5, 0x6b,
+ 0xc9, 0xf1, 0xb5, 0x65, 0xfe, 0x66, 0x0d, 0xa2, 0xd5, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0x02, 0x81, 0x80, 0x5e, 0x01, 0x5f, 0xb6, 0x59, 0x1d, 0xdc,
+ 0x36, 0xb6, 0x60, 0x36, 0xe6, 0x08, 0xdb, 0xd9, 0xcd, 0xc3, 0x8c, 0x16,
+ 0x9c, 0x98, 0x8d, 0x7f, 0xd3, 0xdb, 0x1d, 0xaa, 0x68, 0x8f, 0xc5, 0xf8,
+ 0xe2, 0x5d, 0xb3, 0x19, 0xc2, 0xc6, 0xf9, 0x51, 0x32, 0x1b, 0x93, 0x6a,
+ 0xdc, 0x50, 0x8e, 0xeb, 0x61, 0x84, 0x03, 0x42, 0x30, 0x98, 0xb1, 0xf7,
+ 0xbd, 0x14, 0x9a, 0x57, 0x36, 0x33, 0x09, 0xd4, 0x3e, 0x90, 0xda, 0xef,
+ 0x09, 0x6e, 0xef, 0x49, 0xb6, 0x60, 0x68, 0x5e, 0x54, 0x17, 0x25, 0x5b,
+ 0x37, 0xe3, 0x35, 0x63, 0x5b, 0x60, 0x3c, 0xbd, 0x50, 0xdf, 0x46, 0x43,
+ 0x08, 0xa4, 0x71, 0x21, 0xf1, 0x30, 0x71, 0xdc, 0xda, 0xd7, 0x6f, 0xd2,
+ 0x18, 0xbd, 0x39, 0xf1, 0xe1, 0xbe, 0xa8, 0x8d, 0x62, 0xdf, 0xa2, 0x3e,
+ 0xb6, 0x15, 0x26, 0xb6, 0x57, 0xbd, 0x63, 0xdb, 0xc1, 0x91, 0xec, 0xb8,
+ 0x01, 0x02, 0x41, 0x00, 0xc6, 0x1a, 0x06, 0x48, 0xf2, 0x12, 0x1c, 0x9f,
+ 0x74, 0x20, 0x5c, 0x85, 0xa2, 0xda, 0xe5, 0x62, 0x96, 0x8d, 0x22, 0x7b,
+ 0x78, 0x73, 0xea, 0xbb, 0x9f, 0x59, 0x42, 0x13, 0x15, 0xc8, 0x11, 0x50,
+ 0x6c, 0x55, 0xf6, 0xdf, 0x8b, 0xfe, 0xc7, 0xdd, 0xa8, 0xca, 0x54, 0x41,
+ 0xe8, 0xce, 0xbe, 0x7d, 0xbd, 0xe2, 0x13, 0x4b, 0x5b, 0x61, 0xeb, 0x69,
+ 0x6c, 0xb1, 0x9b, 0x28, 0x68, 0x5b, 0xd6, 0x01, 0x02, 0x41, 0x00, 0xbd,
+ 0x1e, 0xfe, 0x51, 0x99, 0xb6, 0xe3, 0x84, 0xfe, 0xf1, 0x9e, 0xfd, 0x9c,
+ 0xe7, 0x86, 0x43, 0x68, 0x7f, 0x2f, 0x6a, 0x2a, 0x4c, 0xae, 0xa6, 0x41,
+ 0x1c, 0xf0, 0x10, 0x37, 0x54, 0x23, 0xba, 0x05, 0x0d, 0x18, 0x27, 0x8d,
+ 0xb8, 0xe4, 0x8f, 0xf2, 0x25, 0x73, 0x8a, 0xd7, 0x05, 0x98, 0x6b, 0x3d,
+ 0x55, 0xb7, 0x6f, 0x7c, 0xec, 0x77, 0x61, 0x54, 0x7b, 0xb6, 0x6b, 0x31,
+ 0xec, 0x94, 0xd5, 0x02, 0x41, 0x00, 0x90, 0xa2, 0xa5, 0x9e, 0x12, 0xa7,
+ 0x68, 0xa0, 0x7e, 0xdf, 0xb5, 0xcd, 0x98, 0x26, 0xab, 0xbd, 0xbc, 0x5f,
+ 0xd5, 0x22, 0x42, 0xc2, 0x97, 0x4a, 0x5f, 0x40, 0x82, 0xfe, 0x7e, 0x33,
+ 0xb1, 0x78, 0x7f, 0x70, 0x90, 0x2b, 0x8d, 0x01, 0xfb, 0x18, 0xfa, 0x48,
+ 0xa7, 0x15, 0xec, 0x0d, 0x2e, 0x85, 0x8d, 0xe2, 0x86, 0xe5, 0xc9, 0x15,
+ 0x88, 0x14, 0x53, 0xd8, 0xa4, 0x88, 0xef, 0x10, 0xc6, 0x01, 0x02, 0x41,
+ 0x00, 0xba, 0xe4, 0xaf, 0x14, 0xfa, 0xdf, 0xf6, 0xd5, 0xce, 0x8f, 0xfe,
+ 0xbb, 0xc8, 0x5c, 0x30, 0x9d, 0xda, 0xdd, 0x9d, 0x80, 0xc0, 0x0e, 0x89,
+ 0xa5, 0xb8, 0xc1, 0x1d, 0x28, 0x19, 0x55, 0x67, 0xfd, 0x03, 0xd2, 0xdd,
+ 0xe4, 0xf0, 0xb4, 0x20, 0x03, 0x74, 0x9b, 0xb8, 0x24, 0x23, 0xbb, 0xde,
+ 0xd5, 0x53, 0x86, 0xaa, 0xc1, 0x5d, 0x65, 0xdd, 0xcf, 0xec, 0x8a, 0x59,
+ 0x4a, 0x73, 0xca, 0xc5, 0x85, 0x02, 0x40, 0x00, 0xc4, 0x5e, 0x8d, 0xa4,
+ 0xea, 0xbb, 0x6a, 0x9b, 0xe6, 0x3a, 0x4d, 0xc1, 0xdb, 0xe5, 0x52, 0x38,
+ 0xf9, 0x59, 0x91, 0x2d, 0x90, 0x82, 0xe3, 0x31, 0x1b, 0x48, 0xb7, 0x42,
+ 0xfa, 0x1d, 0x83, 0xd5, 0x3d, 0x02, 0xc2, 0x12, 0x71, 0x10, 0x3a, 0xbd,
+ 0x92, 0x8f, 0x9b, 0xa2, 0x6b, 0x2d, 0x21, 0xa4, 0x65, 0xe9, 0xfa, 0x8c,
+ 0x30, 0x2a, 0x89, 0xce, 0xd0, 0xa7, 0x67, 0xd8, 0x45, 0x84, 0xb0};
+
+ const uint8_t short_integer_without_high_bit[] = {
+ 0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+ 0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+ 0x00, 0xc3, 0x9e, 0x8d, 0xc4, 0x6d, 0x38, 0xe8, 0x0e, 0x9f, 0x84, 0x03,
+ 0x40, 0x8e, 0x81, 0x2e, 0x56, 0x67, 0x78, 0x11, 0x85, 0x27, 0x81, 0x52,
+ 0xf2, 0x1b, 0x3e, 0x5b, 0xf8, 0xab, 0xfc, 0xaf, 0xca, 0x5c, 0x26, 0xd5,
+ 0xfa, 0xd4, 0x55, 0x50, 0x38, 0xb9, 0x9d, 0x89, 0x92, 0x7e, 0x34, 0xcf,
+ 0x37, 0x82, 0x48, 0x2d, 0xaa, 0xc4, 0x6a, 0x0e, 0x93, 0xea, 0xad, 0x8a,
+ 0x33, 0xf0, 0x42, 0x23, 0xe0, 0x4c, 0x98, 0xbf, 0x01, 0x00, 0x1b, 0xfe,
+ 0x06, 0x15, 0xc6, 0xe3, 0x80, 0x79, 0x6d, 0xfe, 0x48, 0xcd, 0x40, 0xbb,
+ 0xf9, 0x58, 0xe6, 0xbf, 0xd5, 0x4c, 0x29, 0x48, 0x53, 0x78, 0x06, 0x03,
+ 0x0d, 0x59, 0xf5, 0x20, 0xe0, 0xe6, 0x8c, 0xb2, 0xf5, 0xd8, 0x61, 0x52,
+ 0x7e, 0x40, 0x83, 0xd7, 0x69, 0xae, 0xd7, 0x75, 0x02, 0x2d, 0x49, 0xd5,
+ 0x15, 0x5b, 0xf1, 0xd9, 0x4d, 0x60, 0x7d, 0x62, 0xa5, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0x02, 0x7f, 0x6d, 0x45, 0x23, 0xeb, 0x95, 0x17, 0x34, 0x88,
+ 0xf6, 0x91, 0xc7, 0x3f, 0x48, 0x5a, 0xe0, 0x87, 0x63, 0x44, 0xae, 0x84,
+ 0xb2, 0x8c, 0x8a, 0xc8, 0xb2, 0x6f, 0x22, 0xf0, 0xc5, 0x21, 0x61, 0x10,
+ 0xa8, 0x69, 0x09, 0x1e, 0x13, 0x7d, 0x94, 0x52, 0x1b, 0x5c, 0xe4, 0x7b,
+ 0xf0, 0x03, 0x8f, 0xbc, 0x72, 0x09, 0xdf, 0x78, 0x84, 0x3e, 0xb9, 0xe5,
+ 0xe6, 0x31, 0x0a, 0x01, 0xf9, 0x32, 0xf8, 0xd6, 0x57, 0xa3, 0x87, 0xe6,
+ 0xf5, 0x98, 0xbc, 0x8e, 0x41, 0xb9, 0x50, 0x17, 0x7b, 0xd3, 0x97, 0x5a,
+ 0x44, 0x3a, 0xee, 0xff, 0x6b, 0xb3, 0x3a, 0x52, 0xe7, 0xa4, 0x96, 0x9a,
+ 0xf6, 0x83, 0xc8, 0x97, 0x1c, 0x63, 0xa1, 0xd6, 0xb3, 0xa8, 0xb2, 0xc7,
+ 0x73, 0x25, 0x0f, 0x58, 0x36, 0xb9, 0x7a, 0x47, 0xa7, 0x4d, 0x30, 0xfe,
+ 0x4d, 0x74, 0x56, 0xe8, 0xfb, 0xd6, 0x50, 0xe5, 0xe0, 0x28, 0x15, 0x02,
+ 0x41, 0x00, 0xeb, 0x15, 0x62, 0xb6, 0x37, 0x41, 0x7c, 0xc5, 0x00, 0x22,
+ 0x2c, 0x5a, 0x5e, 0xe4, 0xb2, 0x11, 0x87, 0x89, 0xad, 0xf4, 0x57, 0x68,
+ 0x90, 0xb7, 0x9f, 0xe2, 0x79, 0x20, 0x6b, 0x98, 0x00, 0x0d, 0x3a, 0x3b,
+ 0xc1, 0xcd, 0x36, 0xf9, 0x27, 0xda, 0x40, 0x36, 0x1d, 0xb8, 0x5c, 0x96,
+ 0xeb, 0x04, 0x08, 0xe1, 0x3f, 0xfa, 0x94, 0x8b, 0x0f, 0xa0, 0xff, 0xc1,
+ 0x51, 0xea, 0x90, 0xad, 0x15, 0xc7, 0x02, 0x41, 0x00, 0xd5, 0x06, 0x45,
+ 0xd7, 0x55, 0x63, 0x1a, 0xf0, 0x89, 0x81, 0xae, 0x87, 0x23, 0xa2, 0x39,
+ 0xfe, 0x3d, 0x82, 0xc7, 0xcb, 0x15, 0xb9, 0xe3, 0xe2, 0x5b, 0xc6, 0xd2,
+ 0x55, 0xdd, 0xab, 0x55, 0x29, 0x7c, 0xda, 0x0e, 0x1c, 0x09, 0xfc, 0x73,
+ 0x0d, 0x01, 0xed, 0x6d, 0x2f, 0x05, 0xd0, 0xd5, 0x1d, 0xce, 0x18, 0x7f,
+ 0xb0, 0xc8, 0x47, 0x77, 0xd2, 0xa9, 0x9e, 0xfc, 0x39, 0x4b, 0x3d, 0x94,
+ 0x33, 0x02, 0x41, 0x00, 0x8f, 0x94, 0x09, 0x2d, 0x17, 0x44, 0x75, 0x0a,
+ 0xf1, 0x10, 0xee, 0x1b, 0xe7, 0xd7, 0x2f, 0xf6, 0xca, 0xdc, 0x49, 0x15,
+ 0x72, 0x09, 0x58, 0x51, 0xfe, 0x61, 0xd8, 0xee, 0xf7, 0x27, 0xe7, 0xe8,
+ 0x2c, 0x47, 0xf1, 0x0f, 0x00, 0x63, 0x5e, 0x76, 0xcb, 0x3f, 0x02, 0x19,
+ 0xe6, 0xda, 0xfa, 0x01, 0x05, 0xd7, 0x65, 0x37, 0x0b, 0x60, 0x7f, 0x94,
+ 0x2a, 0x80, 0x8d, 0x22, 0x81, 0x68, 0x65, 0x63, 0x02, 0x41, 0x00, 0xc2,
+ 0xd4, 0x18, 0xde, 0x47, 0x9e, 0xfb, 0x8d, 0x91, 0x05, 0xc5, 0x3c, 0x9d,
+ 0xcf, 0x8a, 0x60, 0xc7, 0x9b, 0x2b, 0xe5, 0xc6, 0xba, 0x1b, 0xfc, 0xf3,
+ 0xd9, 0x54, 0x97, 0xe9, 0xc4, 0x00, 0x80, 0x90, 0x4a, 0xd2, 0x6a, 0xbc,
+ 0x8b, 0x62, 0x22, 0x3c, 0x68, 0x0c, 0xda, 0xdb, 0xe3, 0xd2, 0x76, 0x8e,
+ 0xff, 0x03, 0x12, 0x09, 0x2a, 0xac, 0x21, 0x44, 0xb7, 0x3e, 0x91, 0x9c,
+ 0x09, 0xf6, 0xd7, 0x02, 0x41, 0x00, 0xc0, 0xa1, 0xbb, 0x70, 0xdc, 0xf8,
+ 0xeb, 0x17, 0x61, 0xd4, 0x8c, 0x7c, 0x3b, 0x82, 0x91, 0x58, 0xff, 0xf9,
+ 0x19, 0xac, 0x3a, 0x73, 0xa7, 0x20, 0xe5, 0x22, 0x02, 0xc4, 0xf6, 0xb9,
+ 0xb9, 0x43, 0x53, 0x35, 0x88, 0xe1, 0x05, 0xb6, 0x43, 0x9b, 0x39, 0xc8,
+ 0x04, 0x4d, 0x2b, 0x01, 0xf7, 0xe6, 0x1b, 0x8d, 0x7e, 0x89, 0xe3, 0x43,
+ 0xd4, 0xf3, 0xab, 0x28, 0xd4, 0x5a, 0x1f, 0x20, 0xea, 0xbe};
+
+ std::vector<uint8_t> input1;
+ std::vector<uint8_t> input2;
+
+ input1.resize(sizeof(short_integer_with_high_bit));
+ input2.resize(sizeof(short_integer_without_high_bit));
+
+ memcpy(&input1.front(), short_integer_with_high_bit,
+ sizeof(short_integer_with_high_bit));
+ memcpy(&input2.front(), short_integer_without_high_bit,
+ sizeof(short_integer_without_high_bit));
+
+ std::unique_ptr<crypto::RSAPrivateKey> keypair1(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input1));
+ std::unique_ptr<crypto::RSAPrivateKey> keypair2(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input2));
+ ASSERT_TRUE(keypair1.get());
+ ASSERT_TRUE(keypair2.get());
+
+ std::vector<uint8_t> output1;
+ std::vector<uint8_t> output2;
+ ASSERT_TRUE(keypair1->ExportPrivateKey(&output1));
+ ASSERT_TRUE(keypair2->ExportPrivateKey(&output2));
+
+ ASSERT_EQ(input1.size(), output1.size());
+ ASSERT_EQ(input2.size(), output2.size());
+ ASSERT_TRUE(0 == memcmp(&output1.front(), &input1.front(),
+ input1.size()));
+ ASSERT_TRUE(0 == memcmp(&output2.front(), &input2.front(),
+ input2.size()));
+}
+
+TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) {
+ std::unique_ptr<crypto::RSAPrivateKey> key_pair(
+ crypto::RSAPrivateKey::Create(512));
+ ASSERT_TRUE(key_pair.get());
+
+ std::unique_ptr<crypto::RSAPrivateKey> key_copy(
+ crypto::RSAPrivateKey::CreateFromKey(key_pair->key()));
+ ASSERT_TRUE(key_copy.get());
+
+ std::vector<uint8_t> privkey;
+ std::vector<uint8_t> pubkey;
+ ASSERT_TRUE(key_pair->ExportPrivateKey(&privkey));
+ ASSERT_TRUE(key_pair->ExportPublicKey(&pubkey));
+
+ std::vector<uint8_t> privkey_copy;
+ std::vector<uint8_t> pubkey_copy;
+ ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy));
+ ASSERT_TRUE(key_copy->ExportPublicKey(&pubkey_copy));
+
+ ASSERT_EQ(privkey, privkey_copy);
+ ASSERT_EQ(pubkey, pubkey_copy);
+}
+
diff --git a/crypto/scoped_capi_types.h b/crypto/scoped_capi_types.h
new file mode 100644
index 0000000..efe0d24
--- /dev/null
+++ b/crypto/scoped_capi_types.h
@@ -0,0 +1,122 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SCOPED_CAPI_TYPES_H_
+#define CRYPTO_SCOPED_CAPI_TYPES_H_
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "crypto/wincrypt_shim.h"
+
+namespace crypto {
+
+// Simple destructor for the Free family of CryptoAPI functions, such as
+// CryptDestroyHash, which take only a single argument to release.
+template <typename CAPIHandle, BOOL (WINAPI *Destroyer)(CAPIHandle)>
+struct CAPIDestroyer {
+ void operator()(CAPIHandle handle) const {
+ if (handle) {
+ BOOL ok = Destroyer(handle);
+ DCHECK(ok);
+ }
+ }
+};
+
+// Destructor for the Close/Release family of CryptoAPI functions, which take
+// a second DWORD parameter indicating flags to use when closing or releasing.
+// This includes functions like CertCloseStore or CryptReleaseContext.
+template <typename CAPIHandle, BOOL (WINAPI *Destroyer)(CAPIHandle, DWORD),
+ DWORD flags>
+struct CAPIDestroyerWithFlags {
+ void operator()(CAPIHandle handle) const {
+ if (handle) {
+ BOOL ok = Destroyer(handle, flags);
+ DCHECK(ok);
+ }
+ }
+};
+
+// scoped_ptr-like class for the CryptoAPI cryptography and certificate
+// handles. Because these handles are defined as integer types, and not
+// pointers, the existing scoped classes, such as scoped_ptr, are insufficient.
+// The semantics are the same as scoped_ptr.
+template <class CAPIHandle, typename FreeProc>
+class ScopedCAPIHandle {
+ public:
+ explicit ScopedCAPIHandle(CAPIHandle handle = NULL) : handle_(handle) {}
+
+ ScopedCAPIHandle(const ScopedCAPIHandle&) = delete;
+ ScopedCAPIHandle& operator=(const ScopedCAPIHandle&) = delete;
+
+ ~ScopedCAPIHandle() {
+ reset();
+ }
+
+ void reset(CAPIHandle handle = NULL) {
+ if (handle_ != handle) {
+ FreeProc free_proc;
+ free_proc(handle_);
+ handle_ = handle;
+ }
+ }
+
+ operator CAPIHandle() const { return handle_; }
+ CAPIHandle get() const { return handle_; }
+
+ CAPIHandle* receive() {
+ CHECK(handle_ == NULL);
+ return &handle_;
+ }
+
+ bool operator==(CAPIHandle handle) const {
+ return handle_ == handle;
+ }
+
+ bool operator!=(CAPIHandle handle) const {
+ return handle_ != handle;
+ }
+
+ void swap(ScopedCAPIHandle& b) {
+ CAPIHandle tmp = b.handle_;
+ b.handle_ = handle_;
+ handle_ = tmp;
+ }
+
+ CAPIHandle release() {
+ CAPIHandle tmp = handle_;
+ handle_ = NULL;
+ return tmp;
+ }
+
+ private:
+ CAPIHandle handle_;
+};
+
+template<class CH, typename FP> inline
+bool operator==(CH h, const ScopedCAPIHandle<CH, FP>& b) {
+ return h == b.get();
+}
+
+template<class CH, typename FP> inline
+bool operator!=(CH h, const ScopedCAPIHandle<CH, FP>& b) {
+ return h != b.get();
+}
+
+typedef ScopedCAPIHandle<
+ HCRYPTPROV,
+ CAPIDestroyerWithFlags<HCRYPTPROV,
+ CryptReleaseContext, 0> > ScopedHCRYPTPROV;
+
+typedef ScopedCAPIHandle<
+ HCRYPTKEY, CAPIDestroyer<HCRYPTKEY, CryptDestroyKey> > ScopedHCRYPTKEY;
+
+typedef ScopedCAPIHandle<
+ HCRYPTHASH, CAPIDestroyer<HCRYPTHASH, CryptDestroyHash> > ScopedHCRYPTHASH;
+
+} // namespace crypto
+
+#endif // CRYPTO_SCOPED_CAPI_TYPES_H_
diff --git a/crypto/scoped_nss_types.h b/crypto/scoped_nss_types.h
new file mode 100644
index 0000000..2a75113
--- /dev/null
+++ b/crypto/scoped_nss_types.h
@@ -0,0 +1,63 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SCOPED_NSS_TYPES_H_
+#define CRYPTO_SCOPED_NSS_TYPES_H_
+
+#include <keyhi.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <plarena.h>
+
+#include <memory>
+
+namespace crypto {
+
+template <typename Type, void (*Destroyer)(Type*)>
+struct NSSDestroyer {
+ void operator()(Type* ptr) const {
+ Destroyer(ptr);
+ }
+};
+
+template <typename Type, void (*Destroyer)(Type*, PRBool), PRBool freeit>
+struct NSSDestroyer1 {
+ void operator()(Type* ptr) const {
+ Destroyer(ptr, freeit);
+ }
+};
+
+// Define some convenient scopers around NSS pointers.
+typedef std::unique_ptr<
+ PK11Context,
+ NSSDestroyer1<PK11Context, PK11_DestroyContext, PR_TRUE>>
+ ScopedPK11Context;
+typedef std::unique_ptr<PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot>>
+ ScopedPK11Slot;
+typedef std::unique_ptr<PK11SlotList,
+ NSSDestroyer<PK11SlotList, PK11_FreeSlotList>>
+ ScopedPK11SlotList;
+typedef std::unique_ptr<PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey>>
+ ScopedPK11SymKey;
+typedef std::unique_ptr<SECKEYPublicKey,
+ NSSDestroyer<SECKEYPublicKey, SECKEY_DestroyPublicKey>>
+ ScopedSECKEYPublicKey;
+typedef std::unique_ptr<
+ SECKEYPrivateKey,
+ NSSDestroyer<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>>
+ ScopedSECKEYPrivateKey;
+typedef std::unique_ptr<
+ SECAlgorithmID,
+ NSSDestroyer1<SECAlgorithmID, SECOID_DestroyAlgorithmID, PR_TRUE>>
+ ScopedSECAlgorithmID;
+typedef std::unique_ptr<SECItem,
+ NSSDestroyer1<SECItem, SECITEM_FreeItem, PR_TRUE>>
+ ScopedSECItem;
+typedef std::unique_ptr<PLArenaPool,
+ NSSDestroyer1<PLArenaPool, PORT_FreeArena, PR_FALSE>>
+ ScopedPLArenaPool;
+
+} // namespace crypto
+
+#endif // CRYPTO_SCOPED_NSS_TYPES_H_
diff --git a/crypto/scoped_openssl_types.h b/crypto/scoped_openssl_types.h
new file mode 100644
index 0000000..e6f895b
--- /dev/null
+++ b/crypto/scoped_openssl_types.h
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SCOPED_OPENSSL_TYPES_H_
+#define CRYPTO_SCOPED_OPENSSL_TYPES_H_
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/mem.h>
+#endif
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <stdint.h>
+
+#include <memory>
+
+// TODO(crbug.com/984789): Remove once all of Chrome OS uses OpenSSL 1.1.
+#include "crypto/libcrypto-compat.h"
+
+namespace crypto {
+
+// Simplistic helper that wraps a call to a deleter function. In a C++11 world,
+// this would be std::function<>. An alternative would be to re-use
+// base::internal::RunnableAdapter<>, but that's far too heavy weight.
+template <typename Type, void (*Destroyer)(Type*)>
+struct OpenSSLDestroyer {
+ void operator()(Type* ptr) const { Destroyer(ptr); }
+};
+
+template <typename PointerType, void (*Destroyer)(PointerType*)>
+using ScopedOpenSSL =
+ std::unique_ptr<PointerType, OpenSSLDestroyer<PointerType, Destroyer>>;
+
+struct OpenSSLFree {
+ void operator()(uint8_t* ptr) const { OPENSSL_free(ptr); }
+};
+
+// Several typedefs are provided for crypto-specific primitives, for
+// short-hand and prevalence.
+using ScopedBIGNUM = ScopedOpenSSL<BIGNUM, BN_free>;
+using ScopedEC_Key = ScopedOpenSSL<EC_KEY, EC_KEY_free>;
+using ScopedBIO = ScopedOpenSSL<BIO, BIO_free_all>;
+using ScopedDSA = ScopedOpenSSL<DSA, DSA_free>;
+using ScopedECDSA_SIG = ScopedOpenSSL<ECDSA_SIG, ECDSA_SIG_free>;
+using ScopedEC_GROUP = ScopedOpenSSL<EC_GROUP, EC_GROUP_free>;
+using ScopedEC_KEY = ScopedOpenSSL<EC_KEY, EC_KEY_free>;
+using ScopedEC_POINT = ScopedOpenSSL<EC_POINT, EC_POINT_free>;
+using ScopedEVP_CIPHER_CTX = ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
+using ScopedEVP_MD_CTX = ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_free>;
+using ScopedEVP_PKEY = ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free>;
+using ScopedEVP_PKEY_CTX = ScopedOpenSSL<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
+using ScopedHMAC_CTX = ScopedOpenSSL<HMAC_CTX, HMAC_CTX_free>;
+using ScopedNETSCAPE_SPKI = ScopedOpenSSL<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
+using ScopedRSA = ScopedOpenSSL<RSA, RSA_free>;
+using ScopedX509 = ScopedOpenSSL<X509, X509_free>;
+
+// The bytes must have been allocated with OPENSSL_malloc.
+using ScopedOpenSSLBytes = std::unique_ptr<uint8_t, OpenSSLFree>;
+
+} // namespace crypto
+
+#endif // CRYPTO_SCOPED_OPENSSL_TYPES_H_
diff --git a/crypto/scoped_test_nss_chromeos_user.cc b/crypto/scoped_test_nss_chromeos_user.cc
new file mode 100644
index 0000000..623c509
--- /dev/null
+++ b/crypto/scoped_test_nss_chromeos_user.cc
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/scoped_test_nss_chromeos_user.h"
+
+#include "base/logging.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+
+namespace crypto {
+
+ScopedTestNSSChromeOSUser::ScopedTestNSSChromeOSUser(
+ const std::string& username_hash)
+ : username_hash_(username_hash), constructed_successfully_(false) {
+ if (!temp_dir_.CreateUniqueTempDir())
+ return;
+ // This opens a software DB in the given folder. In production code that is in
+ // the home folder, but for testing the temp folder is used.
+ constructed_successfully_ =
+ InitializeNSSForChromeOSUser(username_hash, temp_dir_.path());
+}
+
+ScopedTestNSSChromeOSUser::~ScopedTestNSSChromeOSUser() {
+ if (constructed_successfully_)
+ CloseChromeOSUserForTesting(username_hash_);
+}
+
+void ScopedTestNSSChromeOSUser::FinishInit() {
+ DCHECK(constructed_successfully_);
+ if (!ShouldInitializeTPMForChromeOSUser(username_hash_))
+ return;
+ WillInitializeTPMForChromeOSUser(username_hash_);
+ InitializePrivateSoftwareSlotForChromeOSUser(username_hash_);
+}
+
+} // namespace crypto
diff --git a/crypto/scoped_test_nss_chromeos_user.h b/crypto/scoped_test_nss_chromeos_user.h
new file mode 100644
index 0000000..e1517d0
--- /dev/null
+++ b/crypto/scoped_test_nss_chromeos_user.h
@@ -0,0 +1,44 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
+#define CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
+
+#include <string>
+
+#include "base/files/scoped_temp_dir.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Opens a persistent NSS software database in a temporary directory for the
+// user with |username_hash|. This database will be used for both the user's
+// public and private slot.
+class CRYPTO_EXPORT ScopedTestNSSChromeOSUser {
+ public:
+ // Opens the software database and sets the public slot for the user. The
+ // private slot will not be initialized until FinishInit() is called.
+ explicit ScopedTestNSSChromeOSUser(const std::string& username_hash);
+
+ ScopedTestNSSChromeOSUser(const ScopedTestNSSChromeOSUser&) = delete;
+ ScopedTestNSSChromeOSUser& operator=(const ScopedTestNSSChromeOSUser&) = delete;
+
+ ~ScopedTestNSSChromeOSUser();
+
+ std::string username_hash() const { return username_hash_; }
+ bool constructed_successfully() const { return constructed_successfully_; }
+
+ // Completes initialization of user. Causes any waiting private slot callbacks
+ // to run, see GetPrivateSlotForChromeOSUser().
+ void FinishInit();
+
+ private:
+ const std::string username_hash_;
+ base::ScopedTempDir temp_dir_;
+ bool constructed_successfully_;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
diff --git a/crypto/scoped_test_nss_db.cc b/crypto/scoped_test_nss_db.cc
new file mode 100644
index 0000000..73614fc
--- /dev/null
+++ b/crypto/scoped_test_nss_db.cc
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/scoped_test_nss_db.h"
+
+#include <cert.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+
+namespace crypto {
+
+ScopedTestNSSDB::ScopedTestNSSDB() {
+ EnsureNSSInit();
+ // NSS is allowed to do IO on the current thread since dispatching
+ // to a dedicated thread would still have the affect of blocking
+ // the current thread, due to NSS's internal locking requirements
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ if (!temp_dir_.CreateUniqueTempDir())
+ return;
+
+ const char kTestDescription[] = "Test DB";
+ slot_ = OpenSoftwareNSSDB(temp_dir_.GetPath(), kTestDescription);
+}
+
+ScopedTestNSSDB::~ScopedTestNSSDB() {
+ // Remove trust from any certs in the test DB before closing it. Otherwise NSS
+ // may cache verification results even after the test DB is gone.
+ if (slot_) {
+ CERTCertList* cert_list = PK11_ListCertsInSlot(slot_.get());
+ for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
+ !CERT_LIST_END(node, cert_list);
+ node = CERT_LIST_NEXT(node)) {
+ CERTCertTrust trust = {0};
+ if (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), node->cert, &trust) !=
+ SECSuccess) {
+ LOG(ERROR) << "CERT_ChangeCertTrust failed: " << PORT_GetError();
+ }
+ }
+ CERT_DestroyCertList(cert_list);
+ }
+
+ // Don't close when NSS is < 3.15.1, because it would require an additional
+ // sleep for 1 second after closing the database, due to
+ // http://bugzil.la/875601.
+ if (!NSS_VersionCheck("3.15.1")) {
+ LOG(ERROR) << "NSS version is < 3.15.1, test DB will not be closed.";
+ temp_dir_.Take();
+ return;
+ }
+
+ // NSS is allowed to do IO on the current thread since dispatching
+ // to a dedicated thread would still have the affect of blocking
+ // the current thread, due to NSS's internal locking requirements
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ if (slot_) {
+ SECStatus status = SECMOD_CloseUserDB(slot_.get());
+ if (status != SECSuccess)
+ PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+ }
+
+ if (!temp_dir_.Delete())
+ LOG(ERROR) << "Could not delete temporary directory.";
+}
+
+} // namespace crypto
diff --git a/crypto/scoped_test_nss_db.h b/crypto/scoped_test_nss_db.h
new file mode 100644
index 0000000..f9f5cbe
--- /dev/null
+++ b/crypto/scoped_test_nss_db.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SCOPED_TEST_NSS_DB_H_
+#define CRYPTO_SCOPED_TEST_NSS_DB_H_
+
+#include "base/files/scoped_temp_dir.h"
+#include "crypto/crypto_export.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace crypto {
+
+// Opens a persistent NSS database in a temporary directory.
+// Prior NSS version 3.15.1, because of http://bugzil.la/875601 , the opened DB
+// will not be closed automatically.
+class CRYPTO_EXPORT ScopedTestNSSDB {
+ public:
+ ScopedTestNSSDB();
+ ScopedTestNSSDB(const ScopedTestNSSDB&) = delete;
+ ScopedTestNSSDB& operator=(const ScopedTestNSSDB&) = delete;
+
+ ~ScopedTestNSSDB();
+
+ bool is_open() const { return !!slot_; }
+ PK11SlotInfo* slot() const { return slot_.get(); }
+
+ private:
+ base::ScopedTempDir temp_dir_;
+ ScopedPK11Slot slot_;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_SCOPED_TEST_NSS_DB_H_
diff --git a/crypto/scoped_test_system_nss_key_slot.cc b/crypto/scoped_test_system_nss_key_slot.cc
new file mode 100644
index 0000000..58d5db2
--- /dev/null
+++ b/crypto/scoped_test_system_nss_key_slot.cc
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/scoped_test_system_nss_key_slot.h"
+
+#include "crypto/nss_util_internal.h"
+#include "crypto/scoped_test_nss_db.h"
+
+namespace crypto {
+
+ScopedTestSystemNSSKeySlot::ScopedTestSystemNSSKeySlot()
+ : test_db_(new ScopedTestNSSDB) {
+ if (!test_db_->is_open())
+ return;
+ SetSystemKeySlotForTesting(
+ ScopedPK11Slot(PK11_ReferenceSlot(test_db_->slot())));
+}
+
+ScopedTestSystemNSSKeySlot::~ScopedTestSystemNSSKeySlot() {
+ SetSystemKeySlotForTesting(ScopedPK11Slot());
+}
+
+bool ScopedTestSystemNSSKeySlot::ConstructedSuccessfully() const {
+ return test_db_->is_open();
+}
+
+PK11SlotInfo* ScopedTestSystemNSSKeySlot::slot() const {
+ return test_db_->slot();
+}
+
+} // namespace crypto
diff --git a/crypto/scoped_test_system_nss_key_slot.h b/crypto/scoped_test_system_nss_key_slot.h
new file mode 100644
index 0000000..24af513
--- /dev/null
+++ b/crypto/scoped_test_system_nss_key_slot.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
+#define CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
+
+#include <memory>
+
+#include "crypto/crypto_export.h"
+
+// Forward declaration, from <pk11pub.h>
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+
+namespace crypto {
+
+class ScopedTestNSSDB;
+
+// Opens a persistent NSS software database in a temporary directory and sets
+// the test system slot to the opened database. This helper should be created in
+// tests to fake the system token that is usually provided by the Chaps module.
+// |slot| is exposed through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will
+// return true.
+// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
+// does not have to be called if this helper is used.
+// At most one instance of this helper must be used at a time.
+class CRYPTO_EXPORT ScopedTestSystemNSSKeySlot {
+ public:
+ explicit ScopedTestSystemNSSKeySlot();
+ ScopedTestSystemNssKeySlot(const ScopedTestSystemNssKeySlot&) = delete;
+ ScopedTestSystemNssKeySlot& operator=(const ScopedTestSystemNssKeySlot&) = delete;
+ ~ScopedTestSystemNSSKeySlot();
+
+ bool ConstructedSuccessfully() const;
+ PK11SlotInfo* slot() const;
+
+ private:
+ std::unique_ptr<ScopedTestNSSDB> test_db_;
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
diff --git a/crypto/secure_hash.cc b/crypto/secure_hash.cc
new file mode 100644
index 0000000..4b22afa
--- /dev/null
+++ b/crypto/secure_hash.cc
@@ -0,0 +1,70 @@
+// Copyright 2012 The Chromium Authors
+// 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"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/mem.h>
+#else
+#include <openssl/crypto.h>
+#endif
+#include <openssl/sha.h>
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/pickle.h"
+#include "crypto/openssl_util.h"
+
+namespace crypto {
+
+namespace {
+
+class SecureHashSHA256 : public SecureHash {
+ public:
+ SecureHashSHA256() {
+ SHA256_Init(&ctx_);
+ }
+
+ SecureHashSHA256(const SecureHashSHA256& other) : SecureHash() {
+ memcpy(&ctx_, &other.ctx_, sizeof(ctx_));
+ }
+
+ ~SecureHashSHA256() override {
+ OPENSSL_cleanse(&ctx_, sizeof(ctx_));
+ }
+
+ 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 {
+ ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result(
+ static_cast<unsigned char*>(output), len);
+ SHA256_Final(result.safe_buffer(), &ctx_);
+ }
+
+ SecureHash* Clone() const override {
+ return new SecureHashSHA256(*this);
+ }
+
+ size_t GetHashLength() const override { return SHA256_DIGEST_LENGTH; }
+
+ private:
+ SHA256_CTX ctx_;
+};
+
+} // namespace
+
+SecureHash* SecureHash::Create(Algorithm algorithm) {
+ switch (algorithm) {
+ case SHA256:
+ return new SecureHashSHA256();
+ default:
+ NOTIMPLEMENTED();
+ return NULL;
+ }
+}
+
+} // namespace crypto
diff --git a/crypto/secure_hash.h b/crypto/secure_hash.h
new file mode 100644
index 0000000..41ff5d0
--- /dev/null
+++ b/crypto/secure_hash.h
@@ -0,0 +1,44 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SECURE_HASH_H_
+#define CRYPTO_SECURE_HASH_H_
+
+#include <stddef.h>
+
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// A wrapper to calculate secure hashes incrementally, allowing to
+// be used when the full input is not known in advance.
+class CRYPTO_EXPORT SecureHash {
+ public:
+ enum Algorithm {
+ SHA256,
+ };
+
+ SecureHash(const SecureHash&) = delete;
+ SecureHash& operator=(const SecureHash&) = delete;
+
+ virtual ~SecureHash() {}
+
+ static SecureHash* Create(Algorithm type);
+
+ virtual void Update(const void* input, size_t len) = 0;
+ virtual void Finish(void* output, size_t len) = 0;
+ virtual size_t GetHashLength() const = 0;
+
+ // Create a clone of this SecureHash. The returned clone and this both
+ // represent the same hash state. But from this point on, calling
+ // Update()/Finish() on either doesn't affect the state of the other.
+ virtual SecureHash* Clone() const = 0;
+
+ protected:
+ SecureHash() {}
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_SECURE_HASH_H_
diff --git a/crypto/secure_hash_unittest.cc b/crypto/secure_hash_unittest.cc
new file mode 100644
index 0000000..176841a
--- /dev/null
+++ b/crypto/secure_hash_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2012 The Chromium Authors
+// 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 <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "crypto/sha2.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SecureHashTest, TestUpdate) {
+ // Example B.3 from FIPS 180-2: long message.
+ std::string input3(500000, 'a'); // 'a' repeated half a million times
+ const int kExpectedHashOfInput3[] = {
+ 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
+ 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
+ 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0};
+
+ uint8_t output3[crypto::kSHA256Length];
+
+ std::unique_ptr<crypto::SecureHash> ctx(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ ctx->Update(input3.data(), input3.size());
+ ctx->Update(input3.data(), input3.size());
+
+ ctx->Finish(output3, sizeof(output3));
+ for (size_t i = 0; i < crypto::kSHA256Length; i++)
+ EXPECT_EQ(kExpectedHashOfInput3[i], static_cast<int>(output3[i]));
+}
+
+TEST(SecureHashTest, TestClone) {
+ std::string input1(10001, 'a'); // 'a' repeated 10001 times
+ std::string input2(10001, 'd'); // 'd' repeated 10001 times
+
+ const uint8_t kExpectedHashOfInput1[crypto::kSHA256Length] = {
+ 0x0c, 0xab, 0x99, 0xa0, 0x58, 0x60, 0x0f, 0xfa, 0xad, 0x12, 0x92,
+ 0xd0, 0xc5, 0x3c, 0x05, 0x48, 0xeb, 0xaf, 0x88, 0xdd, 0x1d, 0x01,
+ 0x03, 0x03, 0x45, 0x70, 0x5f, 0x01, 0x8a, 0x81, 0x39, 0x09};
+ const uint8_t kExpectedHashOfInput1And2[crypto::kSHA256Length] = {
+ 0x4c, 0x8e, 0x26, 0x5a, 0xc3, 0x85, 0x1f, 0x1f, 0xa5, 0x04, 0x1c,
+ 0xc7, 0x88, 0x53, 0x1c, 0xc7, 0x80, 0x47, 0x15, 0xfb, 0x47, 0xff,
+ 0x72, 0xb1, 0x28, 0x37, 0xb0, 0x4d, 0x6e, 0x22, 0x2e, 0x4d};
+
+ uint8_t output1[crypto::kSHA256Length];
+ uint8_t output2[crypto::kSHA256Length];
+ uint8_t output3[crypto::kSHA256Length];
+
+ std::unique_ptr<crypto::SecureHash> ctx1(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ ctx1->Update(input1.data(), input1.size());
+
+ std::unique_ptr<crypto::SecureHash> ctx2(ctx1->Clone());
+ std::unique_ptr<crypto::SecureHash> ctx3(ctx2->Clone());
+ // At this point, ctx1, ctx2, and ctx3 are all equivalent and represent the
+ // state after hashing input1.
+
+ // Updating ctx1 and ctx2 with input2 should produce equivalent results.
+ ctx1->Update(input2.data(), input2.size());
+ ctx1->Finish(output1, sizeof(output1));
+
+ ctx2->Update(input2.data(), input2.size());
+ ctx2->Finish(output2, sizeof(output2));
+
+ EXPECT_EQ(0, memcmp(output1, output2, crypto::kSHA256Length));
+ EXPECT_EQ(0,
+ memcmp(output1, kExpectedHashOfInput1And2, crypto::kSHA256Length));
+
+ // Finish() ctx3, which should produce the hash of input1.
+ ctx3->Finish(&output3, sizeof(output3));
+ EXPECT_EQ(0, memcmp(output3, kExpectedHashOfInput1, crypto::kSHA256Length));
+}
+
+TEST(SecureHashTest, TestLength) {
+ std::unique_ptr<crypto::SecureHash> ctx(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ EXPECT_EQ(crypto::kSHA256Length, ctx->GetHashLength());
+}
diff --git a/crypto/secure_util.cc b/crypto/secure_util.cc
new file mode 100644
index 0000000..bf45091
--- /dev/null
+++ b/crypto/secure_util.cc
@@ -0,0 +1,21 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "crypto/secure_util.h"
+
+namespace crypto {
+
+bool SecureMemEqual(const void* s1, const void* s2, size_t n) {
+ const unsigned char* s1_ptr = reinterpret_cast<const unsigned char*>(s1);
+ const unsigned char* s2_ptr = reinterpret_cast<const unsigned char*>(s2);
+ unsigned char tmp = 0;
+ for (size_t i = 0; i < n; ++i, ++s1_ptr, ++s2_ptr)
+ tmp |= *s1_ptr ^ *s2_ptr;
+ return (tmp == 0);
+}
+
+} // namespace crypto
+
diff --git a/crypto/secure_util.h b/crypto/secure_util.h
new file mode 100644
index 0000000..70a23c6
--- /dev/null
+++ b/crypto/secure_util.h
@@ -0,0 +1,29 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SECURE_UTIL_H_
+#define CRYPTO_SECURE_UTIL_H_
+
+#include <stddef.h>
+
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Performs a constant-time comparison of two strings, returning true if the
+// strings are equal.
+//
+// For cryptographic operations, comparison functions such as memcmp() may
+// expose side-channel information about input, allowing an attacker to
+// perform timing analysis to determine what the expected bits should be. In
+// order to avoid such attacks, the comparison must execute in constant time,
+// so as to not to reveal to the attacker where the difference(s) are.
+// For an example attack, see
+// http://groups.google.com/group/keyczar-discuss/browse_thread/thread/5571eca0948b2a13
+CRYPTO_EXPORT bool SecureMemEqual(const void* s1, const void* s2, size_t n);
+
+} // namespace crypto
+
+#endif // CRYPTO_SECURE_UTIL_H_
+
diff --git a/crypto/sha2.cc b/crypto/sha2.cc
new file mode 100644
index 0000000..ad28cb2
--- /dev/null
+++ b/crypto/sha2.cc
@@ -0,0 +1,28 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/sha2.h"
+
+#include <stddef.h>
+
+#include <iterator>
+#include <memory>
+
+#include "crypto/secure_hash.h"
+
+namespace crypto {
+
+void SHA256HashString(const base::StringPiece& str, void* output, size_t len) {
+ std::unique_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256));
+ ctx->Update(str.data(), str.length());
+ ctx->Finish(output, len);
+}
+
+std::string SHA256HashString(const base::StringPiece& str) {
+ std::string output(kSHA256Length, 0);
+ SHA256HashString(str, std::data(output), output.size());
+ return output;
+}
+
+} // namespace crypto
diff --git a/crypto/sha2.h b/crypto/sha2.h
new file mode 100644
index 0000000..ba4523b
--- /dev/null
+++ b/crypto/sha2.h
@@ -0,0 +1,35 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SHA2_H_
+#define CRYPTO_SHA2_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// These functions perform SHA-256 operations.
+//
+// Functions for SHA-384 and SHA-512 can be added when the need arises.
+
+static const size_t kSHA256Length = 32; // Length in bytes of a SHA-256 hash.
+
+// Computes the SHA-256 hash of the input string 'str' and stores the first
+// 'len' bytes of the hash in the output buffer 'output'. If 'len' > 32,
+// only 32 bytes (the full hash) are stored in the 'output' buffer.
+CRYPTO_EXPORT void SHA256HashString(const base::StringPiece& str,
+ void* output, size_t len);
+
+// Convenience version of the above that returns the result in a 32-byte
+// string.
+CRYPTO_EXPORT std::string SHA256HashString(const base::StringPiece& str);
+
+} // namespace crypto
+
+#endif // CRYPTO_SHA2_H_
diff --git a/crypto/sha2_unittest.cc b/crypto/sha2_unittest.cc
new file mode 100644
index 0000000..dcfa27a
--- /dev/null
+++ b/crypto/sha2_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/sha2.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(Sha256Test, Test1) {
+ // Example B.1 from FIPS 180-2: one-block message.
+ std::string input1 = "abc";
+ int expected1[] = { 0xba, 0x78, 0x16, 0xbf,
+ 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3,
+ 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61,
+ 0xf2, 0x00, 0x15, 0xad };
+
+ uint8_t output1[crypto::kSHA256Length];
+ crypto::SHA256HashString(input1, output1, sizeof(output1));
+ for (size_t i = 0; i < crypto::kSHA256Length; i++)
+ EXPECT_EQ(expected1[i], static_cast<int>(output1[i]));
+
+ uint8_t output_truncated1[4]; // 4 bytes == 32 bits
+ crypto::SHA256HashString(input1,
+ output_truncated1, sizeof(output_truncated1));
+ for (size_t i = 0; i < sizeof(output_truncated1); i++)
+ EXPECT_EQ(expected1[i], static_cast<int>(output_truncated1[i]));
+}
+
+TEST(Sha256Test, Test1_String) {
+ // Same as the above, but using the wrapper that returns a std::string.
+ // Example B.1 from FIPS 180-2: one-block message.
+ std::string input1 = "abc";
+ int expected1[] = { 0xba, 0x78, 0x16, 0xbf,
+ 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3,
+ 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61,
+ 0xf2, 0x00, 0x15, 0xad };
+
+ std::string output1 = crypto::SHA256HashString(input1);
+ ASSERT_EQ(crypto::kSHA256Length, output1.size());
+ for (size_t i = 0; i < crypto::kSHA256Length; i++)
+ EXPECT_EQ(expected1[i], static_cast<uint8_t>(output1[i]));
+}
+
+TEST(Sha256Test, Test2) {
+ // Example B.2 from FIPS 180-2: multi-block message.
+ std::string input2 =
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ int expected2[] = { 0x24, 0x8d, 0x6a, 0x61,
+ 0xd2, 0x06, 0x38, 0xb8,
+ 0xe5, 0xc0, 0x26, 0x93,
+ 0x0c, 0x3e, 0x60, 0x39,
+ 0xa3, 0x3c, 0xe4, 0x59,
+ 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4,
+ 0x19, 0xdb, 0x06, 0xc1 };
+
+ uint8_t output2[crypto::kSHA256Length];
+ crypto::SHA256HashString(input2, output2, sizeof(output2));
+ for (size_t i = 0; i < crypto::kSHA256Length; i++)
+ EXPECT_EQ(expected2[i], static_cast<int>(output2[i]));
+
+ uint8_t output_truncated2[6];
+ crypto::SHA256HashString(input2,
+ output_truncated2, sizeof(output_truncated2));
+ for (size_t i = 0; i < sizeof(output_truncated2); i++)
+ EXPECT_EQ(expected2[i], static_cast<int>(output_truncated2[i]));
+}
+
+TEST(Sha256Test, Test3) {
+ // Example B.3 from FIPS 180-2: long message.
+ std::string input3(1000000, 'a'); // 'a' repeated a million times
+ int expected3[] = { 0xcd, 0xc7, 0x6e, 0x5c,
+ 0x99, 0x14, 0xfb, 0x92,
+ 0x81, 0xa1, 0xc7, 0xe2,
+ 0x84, 0xd7, 0x3e, 0x67,
+ 0xf1, 0x80, 0x9a, 0x48,
+ 0xa4, 0x97, 0x20, 0x0e,
+ 0x04, 0x6d, 0x39, 0xcc,
+ 0xc7, 0x11, 0x2c, 0xd0 };
+
+ uint8_t output3[crypto::kSHA256Length];
+ crypto::SHA256HashString(input3, output3, sizeof(output3));
+ for (size_t i = 0; i < crypto::kSHA256Length; i++)
+ EXPECT_EQ(expected3[i], static_cast<int>(output3[i]));
+
+ uint8_t output_truncated3[12];
+ crypto::SHA256HashString(input3,
+ output_truncated3, sizeof(output_truncated3));
+ for (size_t i = 0; i < sizeof(output_truncated3); i++)
+ EXPECT_EQ(expected3[i], static_cast<int>(output_truncated3[i]));
+}
diff --git a/crypto/signature_creator.h b/crypto/signature_creator.h
new file mode 100644
index 0000000..fba3315
--- /dev/null
+++ b/crypto/signature_creator.h
@@ -0,0 +1,75 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SIGNATURE_CREATOR_H_
+#define CRYPTO_SIGNATURE_CREATOR_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#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 {
+
+class RSAPrivateKey;
+
+// Signs data using a bare private key (as opposed to a full certificate).
+// Currently can only sign data using SHA-1 or SHA-256 with RSA PKCS#1v1.5.
+class CRYPTO_EXPORT SignatureCreator {
+ public:
+ // The set of supported hash functions. Extend as required.
+ enum HashAlgorithm {
+ SHA1,
+ SHA256,
+ };
+
+ SignatureCreator(const SignatureCreator&) = delete;
+ SignatureCreator& operator=(const SignatureCreator&) = delete;
+
+ ~SignatureCreator();
+
+ // Create an instance. The caller must ensure that the provided PrivateKey
+ // instance outlives the created SignatureCreator. Uses the HashAlgorithm
+ // specified.
+ static SignatureCreator* Create(RSAPrivateKey* key, HashAlgorithm hash_alg);
+
+
+ // Signs the precomputed |hash_alg| digest |data| using private |key| as
+ // specified in PKCS #1 v1.5.
+ static bool Sign(RSAPrivateKey* key,
+ HashAlgorithm hash_alg,
+ const uint8_t* data,
+ int data_len,
+ std::vector<uint8_t>* signature);
+
+ // Update the signature with more data.
+ bool Update(const uint8_t* data_part, int data_part_len);
+
+ // Finalize the signature.
+ bool Final(std::vector<uint8_t>* signature);
+
+ private:
+ // 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
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_SIGNATURE_CREATOR_H_
diff --git a/crypto/signature_creator_nss.cc b/crypto/signature_creator_nss.cc
new file mode 100644
index 0000000..1554508
--- /dev/null
+++ b/crypto/signature_creator_nss.cc
@@ -0,0 +1,120 @@
+// Copyright 2012 The Chromium Authors
+// 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_creator_unittest.cc b/crypto/signature_creator_unittest.cc
new file mode 100644
index 0000000..1c011f6
--- /dev/null
+++ b/crypto/signature_creator_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright 2012 The Chromium Authors
+// 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 <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/sha1.h"
+#include "crypto/rsa_private_key.h"
+#include "crypto/sha2.h"
+#include "crypto/signature_verifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SignatureCreatorTest, BasicTest) {
+ // Do a verify round trip.
+ std::unique_ptr<crypto::RSAPrivateKey> key_original(
+ crypto::RSAPrivateKey::Create(1024));
+ ASSERT_TRUE(key_original.get());
+
+ std::vector<uint8_t> key_info;
+ key_original->ExportPrivateKey(&key_info);
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+ ASSERT_TRUE(key.get());
+
+ std::unique_ptr<crypto::SignatureCreator> signer(
+ crypto::SignatureCreator::Create(key.get(),
+ crypto::SignatureCreator::SHA1));
+ ASSERT_TRUE(signer.get());
+
+ std::string data("Hello, World!");
+ ASSERT_TRUE(signer->Update(reinterpret_cast<const uint8_t*>(data.c_str()),
+ data.size()));
+
+ std::vector<uint8_t> signature;
+ ASSERT_TRUE(signer->Final(&signature));
+
+ std::vector<uint8_t> public_key_info;
+ ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
+
+ crypto::SignatureVerifier verifier;
+ ASSERT_TRUE(verifier.VerifyInit(
+ crypto::SignatureVerifier::RSA_PKCS1_SHA1, &signature.front(),
+ signature.size(), &public_key_info.front(), public_key_info.size()));
+
+ verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(data.c_str()),
+ data.size());
+ ASSERT_TRUE(verifier.VerifyFinal());
+}
+
+TEST(SignatureCreatorTest, SignDigestTest) {
+ // Do a verify round trip.
+ std::unique_ptr<crypto::RSAPrivateKey> key_original(
+ crypto::RSAPrivateKey::Create(1024));
+ ASSERT_TRUE(key_original.get());
+
+ std::vector<uint8_t> key_info;
+ key_original->ExportPrivateKey(&key_info);
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+ ASSERT_TRUE(key.get());
+
+ std::string data("Hello, World!");
+ std::string sha1 = base::SHA1HashString(data);
+ // Sign sha1 of the input data.
+ std::vector<uint8_t> signature;
+ ASSERT_TRUE(crypto::SignatureCreator::Sign(
+ key.get(), crypto::SignatureCreator::SHA1,
+ reinterpret_cast<const uint8_t*>(sha1.c_str()), sha1.size(), &signature));
+
+ std::vector<uint8_t> public_key_info;
+ ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
+
+ // Verify the input data.
+ crypto::SignatureVerifier verifier;
+ ASSERT_TRUE(verifier.VerifyInit(
+ crypto::SignatureVerifier::RSA_PKCS1_SHA1, &signature.front(),
+ signature.size(), &public_key_info.front(), public_key_info.size()));
+
+ verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(data.c_str()),
+ data.size());
+ ASSERT_TRUE(verifier.VerifyFinal());
+}
+
+TEST(SignatureCreatorTest, SignSHA256DigestTest) {
+ // Do a verify round trip.
+ std::unique_ptr<crypto::RSAPrivateKey> key_original(
+ crypto::RSAPrivateKey::Create(1024));
+ ASSERT_TRUE(key_original.get());
+
+ std::vector<uint8_t> key_info;
+ key_original->ExportPrivateKey(&key_info);
+ std::unique_ptr<crypto::RSAPrivateKey> key(
+ crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+ ASSERT_TRUE(key.get());
+
+ std::string data("Hello, World!");
+ std::string sha256 = crypto::SHA256HashString(data);
+ // Sign sha256 of the input data.
+ std::vector<uint8_t> signature;
+ ASSERT_TRUE(crypto::SignatureCreator::Sign(
+ key.get(), crypto::SignatureCreator::HashAlgorithm::SHA256,
+ reinterpret_cast<const uint8_t*>(sha256.c_str()), sha256.size(),
+ &signature));
+
+ std::vector<uint8_t> public_key_info;
+ ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
+
+ // Verify the input data.
+ crypto::SignatureVerifier verifier;
+ ASSERT_TRUE(verifier.VerifyInit(
+ crypto::SignatureVerifier::RSA_PKCS1_SHA256, &signature.front(),
+ signature.size(), &public_key_info.front(), public_key_info.size()));
+
+ verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(data.c_str()),
+ data.size());
+ ASSERT_TRUE(verifier.VerifyFinal());
+}
diff --git a/crypto/signature_verifier.h b/crypto/signature_verifier.h
new file mode 100644
index 0000000..a02f5aa
--- /dev/null
+++ b/crypto/signature_verifier.h
@@ -0,0 +1,134 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SIGNATURE_VERIFIER_H_
+#define CRYPTO_SIGNATURE_VERIFIER_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#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 {
+
+// The SignatureVerifier class verifies a signature using a bare public key
+// (as opposed to a certificate).
+class CRYPTO_EXPORT SignatureVerifier {
+ public:
+ // The set of supported hash functions. Extend as required.
+ enum HashAlgorithm {
+ SHA1,
+ SHA256,
+ };
+
+ // The set of supported signature algorithms. Extend as required.
+ enum SignatureAlgorithm {
+ RSA_PKCS1_SHA1,
+ RSA_PKCS1_SHA256,
+ ECDSA_SHA256,
+ };
+
+ SignatureVerifier();
+ ~SignatureVerifier();
+
+ // Streaming interface:
+
+ // Initiates a signature verification operation. This should be followed
+ // by one or more VerifyUpdate calls and a VerifyFinal call.
+ // NOTE: for RSA-PSS signatures, use VerifyInitRSAPSS instead.
+ //
+ // The signature is encoded according to the signature algorithm.
+ //
+ // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo
+ // structure, which contains not only the public key but also its type
+ // (algorithm):
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ bool VerifyInit(SignatureAlgorithm signature_algorithm,
+ const uint8_t* signature,
+ int signature_len,
+ const uint8_t* public_key_info,
+ int public_key_info_len);
+
+ // Initiates a RSA-PSS signature verification operation. This should be
+ // followed by one or more VerifyUpdate calls and a VerifyFinal call.
+ //
+ // The RSA-PSS signature algorithm parameters are specified with the
+ // |hash_alg|, |mask_hash_alg|, and |salt_len| arguments.
+ //
+ // An RSA-PSS signature is a nonnegative integer encoded as a byte string
+ // (of the same length as the RSA modulus) in big-endian byte order. It
+ // must not be further encoded in an ASN.1 BIT STRING.
+ //
+ // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo
+ // structure, which contains not only the public key but also its type
+ // (algorithm):
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ bool 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);
+
+ // Feeds a piece of the data to the signature verifier.
+ void VerifyUpdate(const uint8_t* data_part, int data_part_len);
+
+ // Concludes a signature verification operation. Returns true if the
+ // signature is valid. Returns false if the signature is invalid or an
+ // error occurred.
+ bool VerifyFinal();
+
+ private:
+#if defined(USE_OPENSSL)
+ bool CommonInit(int pkey_type,
+ const EVP_MD* digest,
+ const uint8_t* signature,
+ int signature_len,
+ 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
+
+#endif // CRYPTO_SIGNATURE_VERIFIER_H_
diff --git a/crypto/signature_verifier_nss.cc b/crypto/signature_verifier_nss.cc
new file mode 100644
index 0000000..2a4a10c
--- /dev/null
+++ b/crypto/signature_verifier_nss.cc
@@ -0,0 +1,213 @@
+// Copyright 2011 The Chromium Authors
+// 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/signature_verifier_unittest.cc b/crypto/signature_verifier_unittest.cc
new file mode 100644
index 0000000..8ea8bfe
--- /dev/null
+++ b/crypto/signature_verifier_unittest.cc
@@ -0,0 +1,1143 @@
+// Copyright 2011 The Chromium Authors
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include "base/numerics/safe_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SignatureVerifierTest, BasicTest) {
+ // The input data in this test comes from real certificates.
+ //
+ // tbs_certificate ("to-be-signed certificate", the part of a certificate that
+ // is signed), signature, and algorithm come from the certificate of
+ // bugs.webkit.org.
+ //
+ // public_key_info comes from the certificate of the issuer, Go Daddy Secure
+ // Certification Authority.
+ //
+ // The bytes in the array initializers are formatted to expose the DER
+ // encoding of the ASN.1 structures.
+
+ // The data that is signed is the following ASN.1 structure:
+ // TBSCertificate ::= SEQUENCE {
+ // ... -- omitted, not important
+ // }
+ const uint8_t tbs_certificate[1017] = {
+ 0x30, 0x82, 0x03, 0xf5, // a SEQUENCE of length 1013 (0x3f5)
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+ 0x00, 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63,
+ 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64,
+ 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+ 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
+ 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
+ 0x69, 0x74, 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79,
+ 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06,
+ 0x03, 0x55, 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32,
+ 0x38, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38,
+ 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
+ 0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
+ 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70,
+ 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49,
+ 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b,
+ 0x13, 0x0c, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72,
+ 0x67, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72,
+ 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
+ 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28,
+ 0xf2, 0xc0, 0x4f, 0xe0, 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5,
+ 0xc9, 0x26, 0x3a, 0x1b, 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0,
+ 0xf0, 0x40, 0x9e, 0x27, 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c,
+ 0xb8, 0x9b, 0x01, 0x2f, 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1,
+ 0x7e, 0x8e, 0xcd, 0xa6, 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff,
+ 0x2a, 0x6d, 0x0e, 0xba, 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39,
+ 0xdc, 0x1e, 0x34, 0xd0, 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca,
+ 0x65, 0xf6, 0x85, 0x3a, 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1,
+ 0xce, 0x88, 0x47, 0xcd, 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb,
+ 0x57, 0xdc, 0xca, 0x99, 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e,
+ 0xe9, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30,
+ 0x82, 0x01, 0xca, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02,
+ 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03,
+ 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16,
+ 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57,
+ 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0,
+ 0x4a, 0xa0, 0x48, 0x86, 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73,
+ 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f,
+ 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e,
+ 0x64, 0x65, 0x64, 0x69, 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e,
+ 0x63, 0x72, 0x6c, 0x30, 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b,
+ 0x30, 0x49, 0x30, 0x47, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd,
+ 0x6d, 0x01, 0x07, 0x17, 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
+ 0x6f, 0x72, 0x79, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
+ 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74,
+ 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64,
+ 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69,
+ 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48,
+ 0xdf, 0x60, 0x32, 0xcc, 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5,
+ 0x9c, 0x16, 0x58, 0x32, 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32,
+ 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76,
+ 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04,
+ 0x1c, 0x30, 0x1a, 0x82, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69,
+ 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69,
+ 0x74, 0x2e, 0x6f, 0x72, 0x67};
+
+ // RSA signature, a big integer in the big-endian byte order.
+ const uint8_t signature[256] = {
+ 0x1e, 0x6a, 0xe7, 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f,
+ 0x99, 0xb4, 0x18, 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37,
+ 0xf4, 0x7d, 0xd5, 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82,
+ 0x56, 0xe3, 0x94, 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01,
+ 0x64, 0xd3, 0x7c, 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01,
+ 0x74, 0xe8, 0x35, 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98,
+ 0x95, 0x24, 0x9e, 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56,
+ 0x8d, 0x23, 0x9c, 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8,
+ 0xa0, 0xe9, 0x7d, 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff,
+ 0x9a, 0x01, 0x31, 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d,
+ 0xbb, 0xbb, 0xcd, 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84,
+ 0x71, 0x08, 0xd2, 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8,
+ 0x12, 0x6a, 0x6f, 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9,
+ 0xe0, 0xb5, 0xb3, 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2,
+ 0xca, 0x20, 0xd3, 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94,
+ 0x93, 0x8c, 0x64, 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3,
+ 0xd3, 0xc1, 0x50, 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a,
+ 0x7a, 0x21, 0x87, 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e,
+ 0xbe, 0xcd, 0x70, 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08,
+ 0x01, 0x6f, 0x37, 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd,
+ 0x35, 0x52, 0xdd, 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8,
+ 0x3c, 0xd8, 0x48, 0x8a};
+
+ // The public key is specified as the following ASN.1 structure:
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ const uint8_t public_key_info[294] = {
+ 0x30, 0x82, 0x01, 0x22, // a SEQUENCE of length 290 (0x122)
+ // algorithm
+ 0x30, 0x0d, // a SEQUENCE of length 13
+ 0x06, 0x09, // an OBJECT IDENTIFIER of length 9
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+ 0x00, // a NULL of length 0
+ // subjectPublicKey
+ 0x03, 0x82, 0x01, 0x0f, // a BIT STRING of length 271 (0x10f)
+ 0x00, // number of unused bits
+ 0x30, 0x82, 0x01, 0x0a, // a SEQUENCE of length 266 (0x10a)
+ // modulus
+ 0x02, 0x82, 0x01, 0x01, // an INTEGER of length 257 (0x101)
+ 0x00, 0xc4, 0x2d, 0xd5, 0x15, 0x8c, 0x9c, 0x26, 0x4c, 0xec, 0x32, 0x35,
+ 0xeb, 0x5f, 0xb8, 0x59, 0x01, 0x5a, 0xa6, 0x61, 0x81, 0x59, 0x3b, 0x70,
+ 0x63, 0xab, 0xe3, 0xdc, 0x3d, 0xc7, 0x2a, 0xb8, 0xc9, 0x33, 0xd3, 0x79,
+ 0xe4, 0x3a, 0xed, 0x3c, 0x30, 0x23, 0x84, 0x8e, 0xb3, 0x30, 0x14, 0xb6,
+ 0xb2, 0x87, 0xc3, 0x3d, 0x95, 0x54, 0x04, 0x9e, 0xdf, 0x99, 0xdd, 0x0b,
+ 0x25, 0x1e, 0x21, 0xde, 0x65, 0x29, 0x7e, 0x35, 0xa8, 0xa9, 0x54, 0xeb,
+ 0xf6, 0xf7, 0x32, 0x39, 0xd4, 0x26, 0x55, 0x95, 0xad, 0xef, 0xfb, 0xfe,
+ 0x58, 0x86, 0xd7, 0x9e, 0xf4, 0x00, 0x8d, 0x8c, 0x2a, 0x0c, 0xbd, 0x42,
+ 0x04, 0xce, 0xa7, 0x3f, 0x04, 0xf6, 0xee, 0x80, 0xf2, 0xaa, 0xef, 0x52,
+ 0xa1, 0x69, 0x66, 0xda, 0xbe, 0x1a, 0xad, 0x5d, 0xda, 0x2c, 0x66, 0xea,
+ 0x1a, 0x6b, 0xbb, 0xe5, 0x1a, 0x51, 0x4a, 0x00, 0x2f, 0x48, 0xc7, 0x98,
+ 0x75, 0xd8, 0xb9, 0x29, 0xc8, 0xee, 0xf8, 0x66, 0x6d, 0x0a, 0x9c, 0xb3,
+ 0xf3, 0xfc, 0x78, 0x7c, 0xa2, 0xf8, 0xa3, 0xf2, 0xb5, 0xc3, 0xf3, 0xb9,
+ 0x7a, 0x91, 0xc1, 0xa7, 0xe6, 0x25, 0x2e, 0x9c, 0xa8, 0xed, 0x12, 0x65,
+ 0x6e, 0x6a, 0xf6, 0x12, 0x44, 0x53, 0x70, 0x30, 0x95, 0xc3, 0x9c, 0x2b,
+ 0x58, 0x2b, 0x3d, 0x08, 0x74, 0x4a, 0xf2, 0xbe, 0x51, 0xb0, 0xbf, 0x87,
+ 0xd0, 0x4c, 0x27, 0x58, 0x6b, 0xb5, 0x35, 0xc5, 0x9d, 0xaf, 0x17, 0x31,
+ 0xf8, 0x0b, 0x8f, 0xee, 0xad, 0x81, 0x36, 0x05, 0x89, 0x08, 0x98, 0xcf,
+ 0x3a, 0xaf, 0x25, 0x87, 0xc0, 0x49, 0xea, 0xa7, 0xfd, 0x67, 0xf7, 0x45,
+ 0x8e, 0x97, 0xcc, 0x14, 0x39, 0xe2, 0x36, 0x85, 0xb5, 0x7e, 0x1a, 0x37,
+ 0xfd, 0x16, 0xf6, 0x71, 0x11, 0x9a, 0x74, 0x30, 0x16, 0xfe, 0x13, 0x94,
+ 0xa3, 0x3f, 0x84, 0x0d, 0x4f,
+ // public exponent
+ 0x02, 0x03, // an INTEGER of length 3
+ 0x01, 0x00, 0x01};
+
+ // We use the signature verifier to perform four signature verification
+ // tests.
+ crypto::SignatureVerifier verifier;
+ bool ok;
+
+ // Test 1: feed all of the data to the verifier at once (a single
+ // VerifyUpdate call).
+ ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+ sizeof(signature), public_key_info,
+ sizeof(public_key_info));
+ EXPECT_TRUE(ok);
+ verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate));
+ ok = verifier.VerifyFinal();
+ EXPECT_TRUE(ok);
+
+ // Test 2: feed the data to the verifier in three parts (three VerifyUpdate
+ // calls).
+ ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+ sizeof(signature), public_key_info,
+ sizeof(public_key_info));
+ EXPECT_TRUE(ok);
+ verifier.VerifyUpdate(tbs_certificate, 256);
+ verifier.VerifyUpdate(tbs_certificate + 256, 256);
+ verifier.VerifyUpdate(tbs_certificate + 512, sizeof(tbs_certificate) - 512);
+ ok = verifier.VerifyFinal();
+ EXPECT_TRUE(ok);
+
+ // Test 3: verify the signature with incorrect data.
+ uint8_t bad_tbs_certificate[sizeof(tbs_certificate)];
+ memcpy(bad_tbs_certificate, tbs_certificate, sizeof(tbs_certificate));
+ bad_tbs_certificate[10] += 1; // Corrupt one byte of the data.
+ ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+ sizeof(signature), public_key_info,
+ sizeof(public_key_info));
+ EXPECT_TRUE(ok);
+ verifier.VerifyUpdate(bad_tbs_certificate, sizeof(bad_tbs_certificate));
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+
+ // Test 4: verify a bad signature.
+ uint8_t bad_signature[sizeof(signature)];
+ memcpy(bad_signature, signature, sizeof(signature));
+ bad_signature[10] += 1; // Corrupt one byte of the signature.
+ ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1,
+ bad_signature, sizeof(bad_signature),
+ public_key_info, sizeof(public_key_info));
+
+ // A crypto library (e.g., NSS) may detect that the signature is corrupted
+ // and cause VerifyInit to return false, so it is fine for 'ok' to be false.
+ if (ok) {
+ verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate));
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+ }
+
+ // Test 5: import an invalid key.
+ uint8_t bad_public_key_info[sizeof(public_key_info)];
+ memcpy(bad_public_key_info, public_key_info, sizeof(public_key_info));
+ bad_public_key_info[0] += 1; // Corrupt part of the SPKI syntax.
+ ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+ sizeof(signature), bad_public_key_info,
+ sizeof(bad_public_key_info));
+ EXPECT_FALSE(ok);
+
+ // Test 6: import a key with extra data.
+ uint8_t long_public_key_info[sizeof(public_key_info) + 5];
+ memset(long_public_key_info, 0, sizeof(long_public_key_info));
+ memcpy(long_public_key_info, public_key_info, sizeof(public_key_info));
+ ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+ sizeof(signature), long_public_key_info,
+ sizeof(long_public_key_info));
+ EXPECT_FALSE(ok);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// RSA-PSS signature verification known answer test
+//
+//////////////////////////////////////////////////////////////////////
+
+// The following RSA-PSS signature test vectors come from the pss-vect.txt
+// file downloaded from
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip.
+//
+// For each key, 6 random messages of length between 1 and 256 octets have
+// been RSASSA-PSS signed.
+//
+// Hash function: SHA-1
+// Mask generation function: MGF1 with SHA-1
+// Salt length: 20 octets
+
+// Example 1: A 1024-bit RSA Key Pair"
+
+// RSA modulus n:
+static const char rsa_modulus_n_1[] =
+ "a5 6e 4a 0e 70 10 17 58 9a 51 87 dc 7e a8 41 d1 "
+ "56 f2 ec 0e 36 ad 52 a4 4d fe b1 e6 1f 7a d9 91 "
+ "d8 c5 10 56 ff ed b1 62 b4 c0 f2 83 a1 2a 88 a3 "
+ "94 df f5 26 ab 72 91 cb b3 07 ce ab fc e0 b1 df "
+ "d5 cd 95 08 09 6d 5b 2b 8b 6d f5 d6 71 ef 63 77 "
+ "c0 92 1c b2 3c 27 0a 70 e2 59 8e 6f f8 9d 19 f1 "
+ "05 ac c2 d3 f0 cb 35 f2 92 80 e1 38 6b 6f 64 c4 "
+ "ef 22 e1 e1 f2 0d 0c e8 cf fb 22 49 bd 9a 21 37 ";
+// RSA public exponent e: "
+static const char rsa_public_exponent_e_1[] =
+ "01 00 01 ";
+
+// RSASSA-PSS Signature Example 1.1
+// Message to be signed:
+static const char message_1_1[] =
+ "cd c8 7d a2 23 d7 86 df 3b 45 e0 bb bc 72 13 26 "
+ "d1 ee 2a f8 06 cc 31 54 75 cc 6f 0d 9c 66 e1 b6 "
+ "23 71 d4 5c e2 39 2e 1a c9 28 44 c3 10 10 2f 15 "
+ "6a 0d 8d 52 c1 f4 c4 0b a3 aa 65 09 57 86 cb 76 "
+ "97 57 a6 56 3b a9 58 fe d0 bc c9 84 e8 b5 17 a3 "
+ "d5 f5 15 b2 3b 8a 41 e7 4a a8 67 69 3f 90 df b0 "
+ "61 a6 e8 6d fa ae e6 44 72 c0 0e 5f 20 94 57 29 "
+ "cb eb e7 7f 06 ce 78 e0 8f 40 98 fb a4 1f 9d 61 "
+ "93 c0 31 7e 8b 60 d4 b6 08 4a cb 42 d2 9e 38 08 "
+ "a3 bc 37 2d 85 e3 31 17 0f cb f7 cc 72 d0 b7 1c "
+ "29 66 48 b3 a4 d1 0f 41 62 95 d0 80 7a a6 25 ca "
+ "b2 74 4f d9 ea 8f d2 23 c4 25 37 02 98 28 bd 16 "
+ "be 02 54 6f 13 0f d2 e3 3b 93 6d 26 76 e0 8a ed "
+ "1b 73 31 8b 75 0a 01 67 d0 ";
+// Salt:
+static const char salt_1_1[] =
+ "de e9 59 c7 e0 64 11 36 14 20 ff 80 18 5e d5 7f "
+ "3e 67 76 af ";
+// Signature:
+static const char signature_1_1[] =
+ "90 74 30 8f b5 98 e9 70 1b 22 94 38 8e 52 f9 71 "
+ "fa ac 2b 60 a5 14 5a f1 85 df 52 87 b5 ed 28 87 "
+ "e5 7c e7 fd 44 dc 86 34 e4 07 c8 e0 e4 36 0b c2 "
+ "26 f3 ec 22 7f 9d 9e 54 63 8e 8d 31 f5 05 12 15 "
+ "df 6e bb 9c 2f 95 79 aa 77 59 8a 38 f9 14 b5 b9 "
+ "c1 bd 83 c4 e2 f9 f3 82 a0 d0 aa 35 42 ff ee 65 "
+ "98 4a 60 1b c6 9e b2 8d eb 27 dc a1 2c 82 c2 d4 "
+ "c3 f6 6c d5 00 f1 ff 2b 99 4d 8a 4e 30 cb b3 3c ";
+
+// RSASSA-PSS Signature Example 1.2
+// Message to be signed:
+static const char message_1_2[] =
+ "85 13 84 cd fe 81 9c 22 ed 6c 4c cb 30 da eb 5c "
+ "f0 59 bc 8e 11 66 b7 e3 53 0c 4c 23 3e 2b 5f 8f "
+ "71 a1 cc a5 82 d4 3e cc 72 b1 bc a1 6d fc 70 13 "
+ "22 6b 9e ";
+// Salt:
+static const char salt_1_2[] =
+ "ef 28 69 fa 40 c3 46 cb 18 3d ab 3d 7b ff c9 8f "
+ "d5 6d f4 2d ";
+// Signature:
+static const char signature_1_2[] =
+ "3e f7 f4 6e 83 1b f9 2b 32 27 41 42 a5 85 ff ce "
+ "fb dc a7 b3 2a e9 0d 10 fb 0f 0c 72 99 84 f0 4e "
+ "f2 9a 9d f0 78 07 75 ce 43 73 9b 97 83 83 90 db "
+ "0a 55 05 e6 3d e9 27 02 8d 9d 29 b2 19 ca 2c 45 "
+ "17 83 25 58 a5 5d 69 4a 6d 25 b9 da b6 60 03 c4 "
+ "cc cd 90 78 02 19 3b e5 17 0d 26 14 7d 37 b9 35 "
+ "90 24 1b e5 1c 25 05 5f 47 ef 62 75 2c fb e2 14 "
+ "18 fa fe 98 c2 2c 4d 4d 47 72 4f db 56 69 e8 43 ";
+
+// RSASSA-PSS Signature Example 1.3
+// Message to be signed:
+static const char message_1_3[] =
+ "a4 b1 59 94 17 61 c4 0c 6a 82 f2 b8 0d 1b 94 f5 "
+ "aa 26 54 fd 17 e1 2d 58 88 64 67 9b 54 cd 04 ef "
+ "8b d0 30 12 be 8d c3 7f 4b 83 af 79 63 fa ff 0d "
+ "fa 22 54 77 43 7c 48 01 7f f2 be 81 91 cf 39 55 "
+ "fc 07 35 6e ab 3f 32 2f 7f 62 0e 21 d2 54 e5 db "
+ "43 24 27 9f e0 67 e0 91 0e 2e 81 ca 2c ab 31 c7 "
+ "45 e6 7a 54 05 8e b5 0d 99 3c db 9e d0 b4 d0 29 "
+ "c0 6d 21 a9 4c a6 61 c3 ce 27 fa e1 d6 cb 20 f4 "
+ "56 4d 66 ce 47 67 58 3d 0e 5f 06 02 15 b5 90 17 "
+ "be 85 ea 84 89 39 12 7b d8 c9 c4 d4 7b 51 05 6c "
+ "03 1c f3 36 f1 7c 99 80 f3 b8 f5 b9 b6 87 8e 8b "
+ "79 7a a4 3b 88 26 84 33 3e 17 89 3f e9 ca a6 aa "
+ "29 9f 7e d1 a1 8e e2 c5 48 64 b7 b2 b9 9b 72 61 "
+ "8f b0 25 74 d1 39 ef 50 f0 19 c9 ee f4 16 97 13 "
+ "38 e7 d4 70 ";
+// Salt:
+static const char salt_1_3[] =
+ "71 0b 9c 47 47 d8 00 d4 de 87 f1 2a fd ce 6d f1 "
+ "81 07 cc 77 ";
+// Signature:
+static const char signature_1_3[] =
+ "66 60 26 fb a7 1b d3 e7 cf 13 15 7c c2 c5 1a 8e "
+ "4a a6 84 af 97 78 f9 18 49 f3 43 35 d1 41 c0 01 "
+ "54 c4 19 76 21 f9 62 4a 67 5b 5a bc 22 ee 7d 5b "
+ "aa ff aa e1 c9 ba ca 2c c3 73 b3 f3 3e 78 e6 14 "
+ "3c 39 5a 91 aa 7f ac a6 64 eb 73 3a fd 14 d8 82 "
+ "72 59 d9 9a 75 50 fa ca 50 1e f2 b0 4e 33 c2 3a "
+ "a5 1f 4b 9e 82 82 ef db 72 8c c0 ab 09 40 5a 91 "
+ "60 7c 63 69 96 1b c8 27 0d 2d 4f 39 fc e6 12 b1 ";
+
+// RSASSA-PSS Signature Example 1.4
+// Message to be signed:
+static const char message_1_4[] =
+ "bc 65 67 47 fa 9e af b3 f0 ";
+// Salt:
+static const char salt_1_4[] =
+ "05 6f 00 98 5d e1 4d 8e f5 ce a9 e8 2f 8c 27 be "
+ "f7 20 33 5e ";
+// Signature:
+static const char signature_1_4[] =
+ "46 09 79 3b 23 e9 d0 93 62 dc 21 bb 47 da 0b 4f "
+ "3a 76 22 64 9a 47 d4 64 01 9b 9a ea fe 53 35 9c "
+ "17 8c 91 cd 58 ba 6b cb 78 be 03 46 a7 bc 63 7f "
+ "4b 87 3d 4b ab 38 ee 66 1f 19 96 34 c5 47 a1 ad "
+ "84 42 e0 3d a0 15 b1 36 e5 43 f7 ab 07 c0 c1 3e "
+ "42 25 b8 de 8c ce 25 d4 f6 eb 84 00 f8 1f 7e 18 "
+ "33 b7 ee 6e 33 4d 37 09 64 ca 79 fd b8 72 b4 d7 "
+ "52 23 b5 ee b0 81 01 59 1f b5 32 d1 55 a6 de 87 ";
+
+// RSASSA-PSS Signature Example 1.5
+// Message to be signed:
+static const char message_1_5[] =
+ "b4 55 81 54 7e 54 27 77 0c 76 8e 8b 82 b7 55 64 "
+ "e0 ea 4e 9c 32 59 4d 6b ff 70 65 44 de 0a 87 76 "
+ "c7 a8 0b 45 76 55 0e ee 1b 2a ca bc 7e 8b 7d 3e "
+ "f7 bb 5b 03 e4 62 c1 10 47 ea dd 00 62 9a e5 75 "
+ "48 0a c1 47 0f e0 46 f1 3a 2b f5 af 17 92 1d c4 "
+ "b0 aa 8b 02 be e6 33 49 11 65 1d 7f 85 25 d1 0f "
+ "32 b5 1d 33 be 52 0d 3d df 5a 70 99 55 a3 df e7 "
+ "82 83 b9 e0 ab 54 04 6d 15 0c 17 7f 03 7f dc cc "
+ "5b e4 ea 5f 68 b5 e5 a3 8c 9d 7e dc cc c4 97 5f "
+ "45 5a 69 09 b4 ";
+// Salt:
+static const char salt_1_5[] =
+ "80 e7 0f f8 6a 08 de 3e c6 09 72 b3 9b 4f bf dc "
+ "ea 67 ae 8e ";
+// Signature:
+static const char signature_1_5[] =
+ "1d 2a ad 22 1c a4 d3 1d df 13 50 92 39 01 93 98 "
+ "e3 d1 4b 32 dc 34 dc 5a f4 ae ae a3 c0 95 af 73 "
+ "47 9c f0 a4 5e 56 29 63 5a 53 a0 18 37 76 15 b1 "
+ "6c b9 b1 3b 3e 09 d6 71 eb 71 e3 87 b8 54 5c 59 "
+ "60 da 5a 64 77 6e 76 8e 82 b2 c9 35 83 bf 10 4c "
+ "3f db 23 51 2b 7b 4e 89 f6 33 dd 00 63 a5 30 db "
+ "45 24 b0 1c 3f 38 4c 09 31 0e 31 5a 79 dc d3 d6 "
+ "84 02 2a 7f 31 c8 65 a6 64 e3 16 97 8b 75 9f ad ";
+
+// RSASSA-PSS Signature Example 1.6
+// Message to be signed:
+static const char message_1_6[] =
+ "10 aa e9 a0 ab 0b 59 5d 08 41 20 7b 70 0d 48 d7 "
+ "5f ae dd e3 b7 75 cd 6b 4c c8 8a e0 6e 46 94 ec "
+ "74 ba 18 f8 52 0d 4f 5e a6 9c bb e7 cc 2b eb a4 "
+ "3e fd c1 02 15 ac 4e b3 2d c3 02 a1 f5 3d c6 c4 "
+ "35 22 67 e7 93 6c fe bf 7c 8d 67 03 57 84 a3 90 "
+ "9f a8 59 c7 b7 b5 9b 8e 39 c5 c2 34 9f 18 86 b7 "
+ "05 a3 02 67 d4 02 f7 48 6a b4 f5 8c ad 5d 69 ad "
+ "b1 7a b8 cd 0c e1 ca f5 02 5a f4 ae 24 b1 fb 87 "
+ "94 c6 07 0c c0 9a 51 e2 f9 91 13 11 e3 87 7d 00 "
+ "44 c7 1c 57 a9 93 39 50 08 80 6b 72 3a c3 83 73 "
+ "d3 95 48 18 18 52 8c 1e 70 53 73 92 82 05 35 29 "
+ "51 0e 93 5c d0 fa 77 b8 fa 53 cc 2d 47 4b d4 fb "
+ "3c c5 c6 72 d6 ff dc 90 a0 0f 98 48 71 2c 4b cf "
+ "e4 6c 60 57 36 59 b1 1e 64 57 e8 61 f0 f6 04 b6 "
+ "13 8d 14 4f 8c e4 e2 da 73 ";
+// Salt:
+static const char salt_1_6[] =
+ "a8 ab 69 dd 80 1f 00 74 c2 a1 fc 60 64 98 36 c6 "
+ "16 d9 96 81 ";
+// Signature:
+static const char signature_1_6[] =
+ "2a 34 f6 12 5e 1f 6b 0b f9 71 e8 4f bd 41 c6 32 "
+ "be 8f 2c 2a ce 7d e8 b6 92 6e 31 ff 93 e9 af 98 "
+ "7f bc 06 e5 1e 9b e1 4f 51 98 f9 1f 3f 95 3b d6 "
+ "7d a6 0a 9d f5 97 64 c3 dc 0f e0 8e 1c be f0 b7 "
+ "5f 86 8d 10 ad 3f ba 74 9f ef 59 fb 6d ac 46 a0 "
+ "d6 e5 04 36 93 31 58 6f 58 e4 62 8f 39 aa 27 89 "
+ "82 54 3b c0 ee b5 37 dc 61 95 80 19 b3 94 fb 27 "
+ "3f 21 58 58 a0 a0 1a c4 d6 50 b9 55 c6 7f 4c 58 ";
+
+// Example 9: A 1536-bit RSA Key Pair
+
+// RSA modulus n:
+static const char rsa_modulus_n_9[] =
+ "e6 bd 69 2a c9 66 45 79 04 03 fd d0 f5 be b8 b9 "
+ "bf 92 ed 10 00 7f c3 65 04 64 19 dd 06 c0 5c 5b "
+ "5b 2f 48 ec f9 89 e4 ce 26 91 09 97 9c bb 40 b4 "
+ "a0 ad 24 d2 24 83 d1 ee 31 5a d4 cc b1 53 42 68 "
+ "35 26 91 c5 24 f6 dd 8e 6c 29 d2 24 cf 24 69 73 "
+ "ae c8 6c 5b f6 b1 40 1a 85 0d 1b 9a d1 bb 8c bc "
+ "ec 47 b0 6f 0f 8c 7f 45 d3 fc 8f 31 92 99 c5 43 "
+ "3d db c2 b3 05 3b 47 de d2 ec d4 a4 ca ef d6 14 "
+ "83 3d c8 bb 62 2f 31 7e d0 76 b8 05 7f e8 de 3f "
+ "84 48 0a d5 e8 3e 4a 61 90 4a 4f 24 8f b3 97 02 "
+ "73 57 e1 d3 0e 46 31 39 81 5c 6f d4 fd 5a c5 b8 "
+ "17 2a 45 23 0e cb 63 18 a0 4f 14 55 d8 4e 5a 8b ";
+// RSA public exponent e:
+static const char rsa_public_exponent_e_9[] =
+ "01 00 01 ";
+
+// RSASSA-PSS Signature Example 9.1
+// Message to be signed:
+static const char message_9_1[] =
+ "a8 8e 26 58 55 e9 d7 ca 36 c6 87 95 f0 b3 1b 59 "
+ "1c d6 58 7c 71 d0 60 a0 b3 f7 f3 ea ef 43 79 59 "
+ "22 02 8b c2 b6 ad 46 7c fc 2d 7f 65 9c 53 85 aa "
+ "70 ba 36 72 cd de 4c fe 49 70 cc 79 04 60 1b 27 "
+ "88 72 bf 51 32 1c 4a 97 2f 3c 95 57 0f 34 45 d4 "
+ "f5 79 80 e0 f2 0d f5 48 46 e6 a5 2c 66 8f 12 88 "
+ "c0 3f 95 00 6e a3 2f 56 2d 40 d5 2a f9 fe b3 2f "
+ "0f a0 6d b6 5b 58 8a 23 7b 34 e5 92 d5 5c f9 79 "
+ "f9 03 a6 42 ef 64 d2 ed 54 2a a8 c7 7d c1 dd 76 "
+ "2f 45 a5 93 03 ed 75 e5 41 ca 27 1e 2b 60 ca 70 "
+ "9e 44 fa 06 61 13 1e 8d 5d 41 63 fd 8d 39 85 66 "
+ "ce 26 de 87 30 e7 2f 9c ca 73 76 41 c2 44 15 94 "
+ "20 63 70 28 df 0a 18 07 9d 62 08 ea 8b 47 11 a2 "
+ "c7 50 f5 ";
+// Salt:
+static const char salt_9_1[] =
+ "c0 a4 25 31 3d f8 d7 56 4b d2 43 4d 31 15 23 d5 "
+ "25 7e ed 80 ";
+// Signature:
+static const char signature_9_1[] =
+ "58 61 07 22 6c 3c e0 13 a7 c8 f0 4d 1a 6a 29 59 "
+ "bb 4b 8e 20 5b a4 3a 27 b5 0f 12 41 11 bc 35 ef "
+ "58 9b 03 9f 59 32 18 7c b6 96 d7 d9 a3 2c 0c 38 "
+ "30 0a 5c dd a4 83 4b 62 d2 eb 24 0a f3 3f 79 d1 "
+ "3d fb f0 95 bf 59 9e 0d 96 86 94 8c 19 64 74 7b "
+ "67 e8 9c 9a ba 5c d8 50 16 23 6f 56 6c c5 80 2c "
+ "b1 3e ad 51 bc 7c a6 be f3 b9 4d cb db b1 d5 70 "
+ "46 97 71 df 0e 00 b1 a8 a0 67 77 47 2d 23 16 27 "
+ "9e da e8 64 74 66 8d 4e 1e ff f9 5f 1d e6 1c 60 "
+ "20 da 32 ae 92 bb f1 65 20 fe f3 cf 4d 88 f6 11 "
+ "21 f2 4b bd 9f e9 1b 59 ca f1 23 5b 2a 93 ff 81 "
+ "fc 40 3a dd f4 eb de a8 49 34 a9 cd af 8e 1a 9e ";
+
+// RSASSA-PSS Signature Example 9.2
+// Message to be signed:
+static const char message_9_2[] =
+ "c8 c9 c6 af 04 ac da 41 4d 22 7e f2 3e 08 20 c3 "
+ "73 2c 50 0d c8 72 75 e9 5b 0d 09 54 13 99 3c 26 "
+ "58 bc 1d 98 85 81 ba 87 9c 2d 20 1f 14 cb 88 ce "
+ "d1 53 a0 19 69 a7 bf 0a 7b e7 9c 84 c1 48 6b c1 "
+ "2b 3f a6 c5 98 71 b6 82 7c 8c e2 53 ca 5f ef a8 "
+ "a8 c6 90 bf 32 6e 8e 37 cd b9 6d 90 a8 2e ba b6 "
+ "9f 86 35 0e 18 22 e8 bd 53 6a 2e ";
+// Salt:
+static const char salt_9_2[] =
+ "b3 07 c4 3b 48 50 a8 da c2 f1 5f 32 e3 78 39 ef "
+ "8c 5c 0e 91 ";
+// Signature:
+static const char signature_9_2[] =
+ "80 b6 d6 43 25 52 09 f0 a4 56 76 38 97 ac 9e d2 "
+ "59 d4 59 b4 9c 28 87 e5 88 2e cb 44 34 cf d6 6d "
+ "d7 e1 69 93 75 38 1e 51 cd 7f 55 4f 2c 27 17 04 "
+ "b3 99 d4 2b 4b e2 54 0a 0e ca 61 95 1f 55 26 7f "
+ "7c 28 78 c1 22 84 2d ad b2 8b 01 bd 5f 8c 02 5f "
+ "7e 22 84 18 a6 73 c0 3d 6b c0 c7 36 d0 a2 95 46 "
+ "bd 67 f7 86 d9 d6 92 cc ea 77 8d 71 d9 8c 20 63 "
+ "b7 a7 10 92 18 7a 4d 35 af 10 81 11 d8 3e 83 ea "
+ "e4 6c 46 aa 34 27 7e 06 04 45 89 90 37 88 f1 d5 "
+ "e7 ce e2 5f b4 85 e9 29 49 11 88 14 d6 f2 c3 ee "
+ "36 14 89 01 6f 32 7f b5 bc 51 7e b5 04 70 bf fa "
+ "1a fa 5f 4c e9 aa 0c e5 b8 ee 19 bf 55 01 b9 58 ";
+
+// RSASSA-PSS Signature Example 9.3
+// Message to be signed:
+static const char message_9_3[] =
+ "0a fa d4 2c cd 4f c6 06 54 a5 50 02 d2 28 f5 2a "
+ "4a 5f e0 3b 8b bb 08 ca 82 da ca 55 8b 44 db e1 "
+ "26 6e 50 c0 e7 45 a3 6d 9d 29 04 e3 40 8a bc d1 "
+ "fd 56 99 94 06 3f 4a 75 cc 72 f2 fe e2 a0 cd 89 "
+ "3a 43 af 1c 5b 8b 48 7d f0 a7 16 10 02 4e 4f 6d "
+ "df 9f 28 ad 08 13 c1 aa b9 1b cb 3c 90 64 d5 ff "
+ "74 2d ef fe a6 57 09 41 39 36 9e 5e a6 f4 a9 63 "
+ "19 a5 cc 82 24 14 5b 54 50 62 75 8f ef d1 fe 34 "
+ "09 ae 16 92 59 c6 cd fd 6b 5f 29 58 e3 14 fa ec "
+ "be 69 d2 ca ce 58 ee 55 17 9a b9 b3 e6 d1 ec c1 "
+ "4a 55 7c 5f eb e9 88 59 52 64 fc 5d a1 c5 71 46 "
+ "2e ca 79 8a 18 a1 a4 94 0c da b4 a3 e9 20 09 cc "
+ "d4 2e 1e 94 7b 13 14 e3 22 38 a2 de ce 7d 23 a8 "
+ "9b 5b 30 c7 51 fd 0a 4a 43 0d 2c 54 85 94 ";
+// Salt:
+static const char salt_9_3[] =
+ "9a 2b 00 7e 80 97 8b bb 19 2c 35 4e b7 da 9a ed "
+ "fc 74 db f5 ";
+// Signature:
+static const char signature_9_3[] =
+ "48 44 08 f3 89 8c d5 f5 34 83 f8 08 19 ef bf 27 "
+ "08 c3 4d 27 a8 b2 a6 fa e8 b3 22 f9 24 02 37 f9 "
+ "81 81 7a ca 18 46 f1 08 4d aa 6d 7c 07 95 f6 e5 "
+ "bf 1a f5 9c 38 e1 85 84 37 ce 1f 7e c4 19 b9 8c "
+ "87 36 ad f6 dd 9a 00 b1 80 6d 2b d3 ad 0a 73 77 "
+ "5e 05 f5 2d fe f3 a5 9a b4 b0 81 43 f0 df 05 cd "
+ "1a d9 d0 4b ec ec a6 da a4 a2 12 98 03 e2 00 cb "
+ "c7 77 87 ca f4 c1 d0 66 3a 6c 59 87 b6 05 95 20 "
+ "19 78 2c af 2e c1 42 6d 68 fb 94 ed 1d 4b e8 16 "
+ "a7 ed 08 1b 77 e6 ab 33 0b 3f fc 07 38 20 fe cd "
+ "e3 72 7f cb e2 95 ee 61 a0 50 a3 43 65 86 37 c3 "
+ "fd 65 9c fb 63 73 6d e3 2d 9f 90 d3 c2 f6 3e ca ";
+
+// RSASSA-PSS Signature Example 9.4
+// Message to be signed:
+static const char message_9_4[] =
+ "1d fd 43 b4 6c 93 db 82 62 9b da e2 bd 0a 12 b8 "
+ "82 ea 04 c3 b4 65 f5 cf 93 02 3f 01 05 96 26 db "
+ "be 99 f2 6b b1 be 94 9d dd d1 6d c7 f3 de bb 19 "
+ "a1 94 62 7f 0b 22 44 34 df 7d 87 00 e9 e9 8b 06 "
+ "e3 60 c1 2f db e3 d1 9f 51 c9 68 4e b9 08 9e cb "
+ "b0 a2 f0 45 03 99 d3 f5 9e ac 72 94 08 5d 04 4f "
+ "53 93 c6 ce 73 74 23 d8 b8 6c 41 53 70 d3 89 e3 "
+ "0b 9f 0a 3c 02 d2 5d 00 82 e8 ad 6f 3f 1e f2 4a "
+ "45 c3 cf 82 b3 83 36 70 63 a4 d4 61 3e 42 64 f0 "
+ "1b 2d ac 2e 5a a4 20 43 f8 fb 5f 69 fa 87 1d 14 "
+ "fb 27 3e 76 7a 53 1c 40 f0 2f 34 3b c2 fb 45 a0 "
+ "c7 e0 f6 be 25 61 92 3a 77 21 1d 66 a6 e2 db b4 "
+ "3c 36 63 50 be ae 22 da 3a c2 c1 f5 07 70 96 fc "
+ "b5 c4 bf 25 5f 75 74 35 1a e0 b1 e1 f0 36 32 81 "
+ "7c 08 56 d4 a8 ba 97 af bd c8 b8 58 55 40 2b c5 "
+ "69 26 fc ec 20 9f 9e a8 ";
+// Salt:
+static const char salt_9_4[] =
+ "70 f3 82 bd df 4d 5d 2d d8 8b 3b c7 b7 30 8b e6 "
+ "32 b8 40 45 ";
+// Signature:
+static const char signature_9_4[] =
+ "84 eb eb 48 1b e5 98 45 b4 64 68 ba fb 47 1c 01 "
+ "12 e0 2b 23 5d 84 b5 d9 11 cb d1 92 6e e5 07 4a "
+ "e0 42 44 95 cb 20 e8 23 08 b8 eb b6 5f 41 9a 03 "
+ "fb 40 e7 2b 78 98 1d 88 aa d1 43 05 36 85 17 2c "
+ "97 b2 9c 8b 7b f0 ae 73 b5 b2 26 3c 40 3d a0 ed "
+ "2f 80 ff 74 50 af 78 28 eb 8b 86 f0 02 8b d2 a8 "
+ "b1 76 a4 d2 28 cc ce a1 83 94 f2 38 b0 9f f7 58 "
+ "cc 00 bc 04 30 11 52 35 57 42 f2 82 b5 4e 66 3a "
+ "91 9e 70 9d 8d a2 4a de 55 00 a7 b9 aa 50 22 6e "
+ "0c a5 29 23 e6 c2 d8 60 ec 50 ff 48 0f a5 74 77 "
+ "e8 2b 05 65 f4 37 9f 79 c7 72 d5 c2 da 80 af 9f "
+ "bf 32 5e ce 6f c2 0b 00 96 16 14 be e8 9a 18 3e ";
+
+// RSASSA-PSS Signature Example 9.5
+// Message to be signed:
+static const char message_9_5[] =
+ "1b dc 6e 7c 98 fb 8c f5 4e 9b 09 7b 66 a8 31 e9 "
+ "cf e5 2d 9d 48 88 44 8e e4 b0 97 80 93 ba 1d 7d "
+ "73 ae 78 b3 a6 2b a4 ad 95 cd 28 9c cb 9e 00 52 "
+ "26 bb 3d 17 8b cc aa 82 1f b0 44 a4 e2 1e e9 76 "
+ "96 c1 4d 06 78 c9 4c 2d ae 93 b0 ad 73 92 22 18 "
+ "55 3d aa 7e 44 eb e5 77 25 a7 a4 5c c7 2b 9b 21 "
+ "38 a6 b1 7c 8d b4 11 ce 82 79 ee 12 41 af f0 a8 "
+ "be c6 f7 7f 87 ed b0 c6 9c b2 72 36 e3 43 5a 80 "
+ "0b 19 2e 4f 11 e5 19 e3 fe 30 fc 30 ea cc ca 4f "
+ "bb 41 76 90 29 bf 70 8e 81 7a 9e 68 38 05 be 67 "
+ "fa 10 09 84 68 3b 74 83 8e 3b cf fa 79 36 6e ed "
+ "1d 48 1c 76 72 91 18 83 8f 31 ba 8a 04 8a 93 c1 "
+ "be 44 24 59 8e 8d f6 32 8b 7a 77 88 0a 3f 9c 7e "
+ "2e 8d fc a8 eb 5a 26 fb 86 bd c5 56 d4 2b be 01 "
+ "d9 fa 6e d8 06 46 49 1c 93 41 ";
+// Salt:
+static const char salt_9_5[] =
+ "d6 89 25 7a 86 ef fa 68 21 2c 5e 0c 61 9e ca 29 "
+ "5f b9 1b 67 ";
+// Signature:
+static const char signature_9_5[] =
+ "82 10 2d f8 cb 91 e7 17 99 19 a0 4d 26 d3 35 d6 "
+ "4f bc 2f 87 2c 44 83 39 43 24 1d e8 45 48 10 27 "
+ "4c df 3d b5 f4 2d 42 3d b1 52 af 71 35 f7 01 42 "
+ "0e 39 b4 94 a6 7c bf d1 9f 91 19 da 23 3a 23 da "
+ "5c 64 39 b5 ba 0d 2b c3 73 ee e3 50 70 01 37 8d "
+ "4a 40 73 85 6b 7f e2 ab a0 b5 ee 93 b2 7f 4a fe "
+ "c7 d4 d1 20 92 1c 83 f6 06 76 5b 02 c1 9e 4d 6a "
+ "1a 3b 95 fa 4c 42 29 51 be 4f 52 13 10 77 ef 17 "
+ "17 97 29 cd df bd b5 69 50 db ac ee fe 78 cb 16 "
+ "64 0a 09 9e a5 6d 24 38 9e ef 10 f8 fe cb 31 ba "
+ "3e a3 b2 27 c0 a8 66 98 bb 89 e3 e9 36 39 05 bf "
+ "22 77 7b 2a 3a a5 21 b6 5b 4c ef 76 d8 3b de 4c ";
+
+// RSASSA-PSS Signature Example 9.6
+// Message to be signed:
+static const char message_9_6[] =
+ "88 c7 a9 f1 36 04 01 d9 0e 53 b1 01 b6 1c 53 25 "
+ "c3 c7 5d b1 b4 11 fb eb 8e 83 0b 75 e9 6b 56 67 "
+ "0a d2 45 40 4e 16 79 35 44 ee 35 4b c6 13 a9 0c "
+ "c9 84 87 15 a7 3d b5 89 3e 7f 6d 27 98 15 c0 c1 "
+ "de 83 ef 8e 29 56 e3 a5 6e d2 6a 88 8d 7a 9c dc "
+ "d0 42 f4 b1 6b 7f a5 1e f1 a0 57 36 62 d1 6a 30 "
+ "2d 0e c5 b2 85 d2 e0 3a d9 65 29 c8 7b 3d 37 4d "
+ "b3 72 d9 5b 24 43 d0 61 b6 b1 a3 50 ba 87 80 7e "
+ "d0 83 af d1 eb 05 c3 f5 2f 4e ba 5e d2 22 77 14 "
+ "fd b5 0b 9d 9d 9d d6 81 4f 62 f6 27 2f cd 5c db "
+ "ce 7a 9e f7 97 ";
+// Salt:
+static const char salt_9_6[] =
+ "c2 5f 13 bf 67 d0 81 67 1a 04 81 a1 f1 82 0d 61 "
+ "3b ba 22 76 ";
+// Signature:
+static const char signature_9_6[] =
+ "a7 fd b0 d2 59 16 5c a2 c8 8d 00 bb f1 02 8a 86 "
+ "7d 33 76 99 d0 61 19 3b 17 a9 64 8e 14 cc bb aa "
+ "de ac aa cd ec 81 5e 75 71 29 4e bb 8a 11 7a f2 "
+ "05 fa 07 8b 47 b0 71 2c 19 9e 3a d0 51 35 c5 04 "
+ "c2 4b 81 70 51 15 74 08 02 48 79 92 ff d5 11 d4 "
+ "af c6 b8 54 49 1e b3 f0 dd 52 31 39 54 2f f1 5c "
+ "31 01 ee 85 54 35 17 c6 a3 c7 94 17 c6 7e 2d d9 "
+ "aa 74 1e 9a 29 b0 6d cb 59 3c 23 36 b3 67 0a e3 "
+ "af ba c7 c3 e7 6e 21 54 73 e8 66 e3 38 ca 24 4d "
+ "e0 0b 62 62 4d 6b 94 26 82 2c ea e9 f8 cc 46 08 "
+ "95 f4 12 50 07 3f d4 5c 5a 1e 7b 42 5c 20 4a 42 "
+ "3a 69 91 59 f6 90 3e 71 0b 37 a7 bb 2b c8 04 9f ";
+
+// Example 10: A 2048-bit RSA Key Pair
+
+// RSA modulus n:
+static const char rsa_modulus_n_10[] =
+ "a5 dd 86 7a c4 cb 02 f9 0b 94 57 d4 8c 14 a7 70 "
+ "ef 99 1c 56 c3 9c 0e c6 5f d1 1a fa 89 37 ce a5 "
+ "7b 9b e7 ac 73 b4 5c 00 17 61 5b 82 d6 22 e3 18 "
+ "75 3b 60 27 c0 fd 15 7b e1 2f 80 90 fe e2 a7 ad "
+ "cd 0e ef 75 9f 88 ba 49 97 c7 a4 2d 58 c9 aa 12 "
+ "cb 99 ae 00 1f e5 21 c1 3b b5 43 14 45 a8 d5 ae "
+ "4f 5e 4c 7e 94 8a c2 27 d3 60 40 71 f2 0e 57 7e "
+ "90 5f be b1 5d fa f0 6d 1d e5 ae 62 53 d6 3a 6a "
+ "21 20 b3 1a 5d a5 da bc 95 50 60 0e 20 f2 7d 37 "
+ "39 e2 62 79 25 fe a3 cc 50 9f 21 df f0 4e 6e ea "
+ "45 49 c5 40 d6 80 9f f9 30 7e ed e9 1f ff 58 73 "
+ "3d 83 85 a2 37 d6 d3 70 5a 33 e3 91 90 09 92 07 "
+ "0d f7 ad f1 35 7c f7 e3 70 0c e3 66 7d e8 3f 17 "
+ "b8 df 17 78 db 38 1d ce 09 cb 4a d0 58 a5 11 00 "
+ "1a 73 81 98 ee 27 cf 55 a1 3b 75 45 39 90 65 82 "
+ "ec 8b 17 4b d5 8d 5d 1f 3d 76 7c 61 37 21 ae 05 ";
+// RSA public exponent e:
+static const char rsa_public_exponent_e_10[] =
+ "01 00 01 ";
+
+// RSASSA-PSS Signature Example 10.1
+// Message to be signed:
+static const char message_10_1[] =
+ "88 31 77 e5 12 6b 9b e2 d9 a9 68 03 27 d5 37 0c "
+ "6f 26 86 1f 58 20 c4 3d a6 7a 3a d6 09 ";
+// Salt:
+static const char salt_10_1[] =
+ "04 e2 15 ee 6f f9 34 b9 da 70 d7 73 0c 87 34 ab "
+ "fc ec de 89 ";
+// Signature:
+static const char signature_10_1[] =
+ "82 c2 b1 60 09 3b 8a a3 c0 f7 52 2b 19 f8 73 54 "
+ "06 6c 77 84 7a bf 2a 9f ce 54 2d 0e 84 e9 20 c5 "
+ "af b4 9f fd fd ac e1 65 60 ee 94 a1 36 96 01 14 "
+ "8e ba d7 a0 e1 51 cf 16 33 17 91 a5 72 7d 05 f2 "
+ "1e 74 e7 eb 81 14 40 20 69 35 d7 44 76 5a 15 e7 "
+ "9f 01 5c b6 6c 53 2c 87 a6 a0 59 61 c8 bf ad 74 "
+ "1a 9a 66 57 02 28 94 39 3e 72 23 73 97 96 c0 2a "
+ "77 45 5d 0f 55 5b 0e c0 1d df 25 9b 62 07 fd 0f "
+ "d5 76 14 ce f1 a5 57 3b aa ff 4e c0 00 69 95 16 "
+ "59 b8 5f 24 30 0a 25 16 0c a8 52 2d c6 e6 72 7e "
+ "57 d0 19 d7 e6 36 29 b8 fe 5e 89 e2 5c c1 5b eb "
+ "3a 64 75 77 55 92 99 28 0b 9b 28 f7 9b 04 09 00 "
+ "0b e2 5b bd 96 40 8b a3 b4 3c c4 86 18 4d d1 c8 "
+ "e6 25 53 fa 1a f4 04 0f 60 66 3d e7 f5 e4 9c 04 "
+ "38 8e 25 7f 1c e8 9c 95 da b4 8a 31 5d 9b 66 b1 "
+ "b7 62 82 33 87 6f f2 38 52 30 d0 70 d0 7e 16 66 ";
+
+// RSASSA-PSS Signature Example 10.2
+// Message to be signed:
+static const char message_10_2[] =
+ "dd 67 0a 01 46 58 68 ad c9 3f 26 13 19 57 a5 0c "
+ "52 fb 77 7c db aa 30 89 2c 9e 12 36 11 64 ec 13 "
+ "97 9d 43 04 81 18 e4 44 5d b8 7b ee 58 dd 98 7b "
+ "34 25 d0 20 71 d8 db ae 80 70 8b 03 9d bb 64 db "
+ "d1 de 56 57 d9 fe d0 c1 18 a5 41 43 74 2e 0f f3 "
+ "c8 7f 74 e4 58 57 64 7a f3 f7 9e b0 a1 4c 9d 75 "
+ "ea 9a 1a 04 b7 cf 47 8a 89 7a 70 8f d9 88 f4 8e "
+ "80 1e db 0b 70 39 df 8c 23 bb 3c 56 f4 e8 21 ac ";
+// Salt:
+static const char salt_10_2[] =
+ "8b 2b dd 4b 40 fa f5 45 c7 78 dd f9 bc 1a 49 cb "
+ "57 f9 b7 1b ";
+// Signature:
+static const char signature_10_2[] =
+ "14 ae 35 d9 dd 06 ba 92 f7 f3 b8 97 97 8a ed 7c "
+ "d4 bf 5f f0 b5 85 a4 0b d4 6c e1 b4 2c d2 70 30 "
+ "53 bb 90 44 d6 4e 81 3d 8f 96 db 2d d7 00 7d 10 "
+ "11 8f 6f 8f 84 96 09 7a d7 5e 1f f6 92 34 1b 28 "
+ "92 ad 55 a6 33 a1 c5 5e 7f 0a 0a d5 9a 0e 20 3a "
+ "5b 82 78 ae c5 4d d8 62 2e 28 31 d8 71 74 f8 ca "
+ "ff 43 ee 6c 46 44 53 45 d8 4a 59 65 9b fb 92 ec "
+ "d4 c8 18 66 86 95 f3 47 06 f6 68 28 a8 99 59 63 "
+ "7f 2b f3 e3 25 1c 24 bd ba 4d 4b 76 49 da 00 22 "
+ "21 8b 11 9c 84 e7 9a 65 27 ec 5b 8a 5f 86 1c 15 "
+ "99 52 e2 3e c0 5e 1e 71 73 46 fa ef e8 b1 68 68 "
+ "25 bd 2b 26 2f b2 53 10 66 c0 de 09 ac de 2e 42 "
+ "31 69 07 28 b5 d8 5e 11 5a 2f 6b 92 b7 9c 25 ab "
+ "c9 bd 93 99 ff 8b cf 82 5a 52 ea 1f 56 ea 76 dd "
+ "26 f4 3b aa fa 18 bf a9 2a 50 4c bd 35 69 9e 26 "
+ "d1 dc c5 a2 88 73 85 f3 c6 32 32 f0 6f 32 44 c3 ";
+
+// RSASSA-PSS Signature Example 10.3
+// Message to be signed:
+static const char message_10_3[] =
+ "48 b2 b6 a5 7a 63 c8 4c ea 85 9d 65 c6 68 28 4b "
+ "08 d9 6b dc aa be 25 2d b0 e4 a9 6c b1 ba c6 01 "
+ "93 41 db 6f be fb 8d 10 6b 0e 90 ed a6 bc c6 c6 "
+ "26 2f 37 e7 ea 9c 7e 5d 22 6b d7 df 85 ec 5e 71 "
+ "ef ff 2f 54 c5 db 57 7f f7 29 ff 91 b8 42 49 1d "
+ "e2 74 1d 0c 63 16 07 df 58 6b 90 5b 23 b9 1a f1 "
+ "3d a1 23 04 bf 83 ec a8 a7 3e 87 1f f9 db ";
+// Salt:
+static const char salt_10_3[] =
+ "4e 96 fc 1b 39 8f 92 b4 46 71 01 0c 0d c3 ef d6 "
+ "e2 0c 2d 73 ";
+// Signature:
+static const char signature_10_3[] =
+ "6e 3e 4d 7b 6b 15 d2 fb 46 01 3b 89 00 aa 5b bb "
+ "39 39 cf 2c 09 57 17 98 70 42 02 6e e6 2c 74 c5 "
+ "4c ff d5 d7 d5 7e fb bf 95 0a 0f 5c 57 4f a0 9d "
+ "3f c1 c9 f5 13 b0 5b 4f f5 0d d8 df 7e df a2 01 "
+ "02 85 4c 35 e5 92 18 01 19 a7 0c e5 b0 85 18 2a "
+ "a0 2d 9e a2 aa 90 d1 df 03 f2 da ae 88 5b a2 f5 "
+ "d0 5a fd ac 97 47 6f 06 b9 3b 5b c9 4a 1a 80 aa "
+ "91 16 c4 d6 15 f3 33 b0 98 89 2b 25 ff ac e2 66 "
+ "f5 db 5a 5a 3b cc 10 a8 24 ed 55 aa d3 5b 72 78 "
+ "34 fb 8c 07 da 28 fc f4 16 a5 d9 b2 22 4f 1f 8b "
+ "44 2b 36 f9 1e 45 6f de a2 d7 cf e3 36 72 68 de "
+ "03 07 a4 c7 4e 92 41 59 ed 33 39 3d 5e 06 55 53 "
+ "1c 77 32 7b 89 82 1b de df 88 01 61 c7 8c d4 19 "
+ "6b 54 19 f7 ac c3 f1 3e 5e bf 16 1b 6e 7c 67 24 "
+ "71 6c a3 3b 85 c2 e2 56 40 19 2a c2 85 96 51 d5 "
+ "0b de 7e b9 76 e5 1c ec 82 8b 98 b6 56 3b 86 bb ";
+
+// RSASSA-PSS Signature Example 10.4
+// Message to be signed:
+static const char message_10_4[] =
+ "0b 87 77 c7 f8 39 ba f0 a6 4b bb db c5 ce 79 75 "
+ "5c 57 a2 05 b8 45 c1 74 e2 d2 e9 05 46 a0 89 c4 "
+ "e6 ec 8a df fa 23 a7 ea 97 ba e6 b6 5d 78 2b 82 "
+ "db 5d 2b 5a 56 d2 2a 29 a0 5e 7c 44 33 e2 b8 2a "
+ "62 1a bb a9 0a dd 05 ce 39 3f c4 8a 84 05 42 45 "
+ "1a ";
+// Salt:
+static const char salt_10_4[] =
+ "c7 cd 69 8d 84 b6 51 28 d8 83 5e 3a 8b 1e b0 e0 "
+ "1c b5 41 ec ";
+// Signature:
+static const char signature_10_4[] =
+ "34 04 7f f9 6c 4d c0 dc 90 b2 d4 ff 59 a1 a3 61 "
+ "a4 75 4b 25 5d 2e e0 af 7d 8b f8 7c 9b c9 e7 dd "
+ "ee de 33 93 4c 63 ca 1c 0e 3d 26 2c b1 45 ef 93 "
+ "2a 1f 2c 0a 99 7a a6 a3 4f 8e ae e7 47 7d 82 cc "
+ "f0 90 95 a6 b8 ac ad 38 d4 ee c9 fb 7e ab 7a d0 "
+ "2d a1 d1 1d 8e 54 c1 82 5e 55 bf 58 c2 a2 32 34 "
+ "b9 02 be 12 4f 9e 90 38 a8 f6 8f a4 5d ab 72 f6 "
+ "6e 09 45 bf 1d 8b ac c9 04 4c 6f 07 09 8c 9f ce "
+ "c5 8a 3a ab 10 0c 80 51 78 15 5f 03 0a 12 4c 45 "
+ "0e 5a cb da 47 d0 e4 f1 0b 80 a2 3f 80 3e 77 4d "
+ "02 3b 00 15 c2 0b 9f 9b be 7c 91 29 63 38 d5 ec "
+ "b4 71 ca fb 03 20 07 b6 7a 60 be 5f 69 50 4a 9f "
+ "01 ab b3 cb 46 7b 26 0e 2b ce 86 0b e8 d9 5b f9 "
+ "2c 0c 8e 14 96 ed 1e 52 85 93 a4 ab b6 df 46 2d "
+ "de 8a 09 68 df fe 46 83 11 68 57 a2 32 f5 eb f6 "
+ "c8 5b e2 38 74 5a d0 f3 8f 76 7a 5f db f4 86 fb ";
+
+// RSASSA-PSS Signature Example 10.5
+// Message to be signed:
+static const char message_10_5[] =
+ "f1 03 6e 00 8e 71 e9 64 da dc 92 19 ed 30 e1 7f "
+ "06 b4 b6 8a 95 5c 16 b3 12 b1 ed df 02 8b 74 97 "
+ "6b ed 6b 3f 6a 63 d4 e7 78 59 24 3c 9c cc dc 98 "
+ "01 65 23 ab b0 24 83 b3 55 91 c3 3a ad 81 21 3b "
+ "b7 c7 bb 1a 47 0a ab c1 0d 44 25 6c 4d 45 59 d9 "
+ "16 ";
+// Salt:
+static const char salt_10_5[] =
+ "ef a8 bf f9 62 12 b2 f4 a3 f3 71 a1 0d 57 41 52 "
+ "65 5f 5d fb ";
+// Signature:
+static const char signature_10_5[] =
+ "7e 09 35 ea 18 f4 d6 c1 d1 7c e8 2e b2 b3 83 6c "
+ "55 b3 84 58 9c e1 9d fe 74 33 63 ac 99 48 d1 f3 "
+ "46 b7 bf dd fe 92 ef d7 8a db 21 fa ef c8 9a de "
+ "42 b1 0f 37 40 03 fe 12 2e 67 42 9a 1c b8 cb d1 "
+ "f8 d9 01 45 64 c4 4d 12 01 16 f4 99 0f 1a 6e 38 "
+ "77 4c 19 4b d1 b8 21 32 86 b0 77 b0 49 9d 2e 7b "
+ "3f 43 4a b1 22 89 c5 56 68 4d ee d7 81 31 93 4b "
+ "b3 dd 65 37 23 6f 7c 6f 3d cb 09 d4 76 be 07 72 "
+ "1e 37 e1 ce ed 9b 2f 7b 40 68 87 bd 53 15 73 05 "
+ "e1 c8 b4 f8 4d 73 3b c1 e1 86 fe 06 cc 59 b6 ed "
+ "b8 f4 bd 7f fe fd f4 f7 ba 9c fb 9d 57 06 89 b5 "
+ "a1 a4 10 9a 74 6a 69 08 93 db 37 99 25 5a 0c b9 "
+ "21 5d 2d 1c d4 90 59 0e 95 2e 8c 87 86 aa 00 11 "
+ "26 52 52 47 0c 04 1d fb c3 ee c7 c3 cb f7 1c 24 "
+ "86 9d 11 5c 0c b4 a9 56 f5 6d 53 0b 80 ab 58 9a "
+ "cf ef c6 90 75 1d df 36 e8 d3 83 f8 3c ed d2 cc ";
+
+// RSASSA-PSS Signature Example 10.6
+// Message to be signed:
+static const char message_10_6[] =
+ "25 f1 08 95 a8 77 16 c1 37 45 0b b9 51 9d fa a1 "
+ "f2 07 fa a9 42 ea 88 ab f7 1e 9c 17 98 00 85 b5 "
+ "55 ae ba b7 62 64 ae 2a 3a b9 3c 2d 12 98 11 91 "
+ "dd ac 6f b5 94 9e b3 6a ee 3c 5d a9 40 f0 07 52 "
+ "c9 16 d9 46 08 fa 7d 97 ba 6a 29 15 b6 88 f2 03 "
+ "23 d4 e9 d9 68 01 d8 9a 72 ab 58 92 dc 21 17 c0 "
+ "74 34 fc f9 72 e0 58 cf 8c 41 ca 4b 4f f5 54 f7 "
+ "d5 06 8a d3 15 5f ce d0 f3 12 5b c0 4f 91 93 37 "
+ "8a 8f 5c 4c 3b 8c b4 dd 6d 1c c6 9d 30 ec ca 6e "
+ "aa 51 e3 6a 05 73 0e 9e 34 2e 85 5b af 09 9d ef "
+ "b8 af d7 ";
+// Salt:
+static const char salt_10_6[] =
+ "ad 8b 15 23 70 36 46 22 4b 66 0b 55 08 85 91 7c "
+ "a2 d1 df 28 ";
+// Signature:
+static const char signature_10_6[] =
+ "6d 3b 5b 87 f6 7e a6 57 af 21 f7 54 41 97 7d 21 "
+ "80 f9 1b 2c 5f 69 2d e8 29 55 69 6a 68 67 30 d9 "
+ "b9 77 8d 97 07 58 cc b2 60 71 c2 20 9f fb d6 12 "
+ "5b e2 e9 6e a8 1b 67 cb 9b 93 08 23 9f da 17 f7 "
+ "b2 b6 4e cd a0 96 b6 b9 35 64 0a 5a 1c b4 2a 91 "
+ "55 b1 c9 ef 7a 63 3a 02 c5 9f 0d 6e e5 9b 85 2c "
+ "43 b3 50 29 e7 3c 94 0f f0 41 0e 8f 11 4e ed 46 "
+ "bb d0 fa e1 65 e4 2b e2 52 8a 40 1c 3b 28 fd 81 "
+ "8e f3 23 2d ca 9f 4d 2a 0f 51 66 ec 59 c4 23 96 "
+ "d6 c1 1d bc 12 15 a5 6f a1 71 69 db 95 75 34 3e "
+ "f3 4f 9d e3 2a 49 cd c3 17 49 22 f2 29 c2 3e 18 "
+ "e4 5d f9 35 31 19 ec 43 19 ce dc e7 a1 7c 64 08 "
+ "8c 1f 6f 52 be 29 63 41 00 b3 91 9d 38 f3 d1 ed "
+ "94 e6 89 1e 66 a7 3b 8f b8 49 f5 87 4d f5 94 59 "
+ "e2 98 c7 bb ce 2e ee 78 2a 19 5a a6 6f e2 d0 73 "
+ "2b 25 e5 95 f5 7d 3e 06 1b 1f c3 e4 06 3b f9 8f ";
+
+struct SignatureExample {
+ const char* message;
+ const char* salt;
+ const char* signature;
+};
+
+struct PSSTestVector {
+ const char* modulus_n;
+ const char* public_exponent_e;
+ SignatureExample example[6];
+};
+
+static const PSSTestVector pss_test[] = {
+ {
+ rsa_modulus_n_1,
+ rsa_public_exponent_e_1,
+ {
+ { message_1_1, salt_1_1, signature_1_1 },
+ { message_1_2, salt_1_2, signature_1_2 },
+ { message_1_3, salt_1_3, signature_1_3 },
+ { message_1_4, salt_1_4, signature_1_4 },
+ { message_1_5, salt_1_5, signature_1_5 },
+ { message_1_6, salt_1_6, signature_1_6 },
+ }
+ },
+ {
+ rsa_modulus_n_9,
+ rsa_public_exponent_e_9,
+ {
+ { message_9_1, salt_9_1, signature_9_1 },
+ { message_9_2, salt_9_2, signature_9_2 },
+ { message_9_3, salt_9_3, signature_9_3 },
+ { message_9_4, salt_9_4, signature_9_4 },
+ { message_9_5, salt_9_5, signature_9_5 },
+ { message_9_6, salt_9_6, signature_9_6 },
+ }
+ },
+ {
+ rsa_modulus_n_10,
+ rsa_public_exponent_e_10,
+ {
+ { message_10_1, salt_10_1, signature_10_1 },
+ { message_10_2, salt_10_2, signature_10_2 },
+ { message_10_3, salt_10_3, signature_10_3 },
+ { message_10_4, salt_10_4, signature_10_4 },
+ { message_10_5, salt_10_5, signature_10_5 },
+ { message_10_6, salt_10_6, signature_10_6 },
+ }
+ },
+};
+
+static uint8_t HexDigitValue(char digit) {
+ if ('0' <= digit && digit <= '9')
+ return digit - '0';
+ if ('a' <= digit && digit <= 'f')
+ return digit - 'a' + 10;
+ return digit - 'A' + 10;
+}
+
+static bool DecodeTestInput(const char* in, std::vector<uint8_t>* out) {
+ out->clear();
+ while (in[0] != '\0') {
+ if (!isxdigit(in[0]) || !isxdigit(in[1]) || in[2] != ' ')
+ return false;
+ uint8_t octet = HexDigitValue(in[0]) * 16 + HexDigitValue(in[1]);
+ out->push_back(octet);
+ in += 3;
+ }
+ return true;
+}
+
+// PrependASN1Length prepends an ASN.1 serialized length to the beginning of
+// |out|.
+static void PrependASN1Length(std::vector<uint8_t>* out, size_t len) {
+ if (len < 128) {
+ out->insert(out->begin(), static_cast<uint8_t>(len));
+ } else if (len < 256) {
+ out->insert(out->begin(), static_cast<uint8_t>(len));
+ out->insert(out->begin(), 0x81);
+ } else if (len < 0x10000) {
+ out->insert(out->begin(), static_cast<uint8_t>(len));
+ out->insert(out->begin(), static_cast<uint8_t>(len >> 8));
+ out->insert(out->begin(), 0x82);
+ } else {
+ CHECK(false) << "ASN.1 length not handled: " << len;
+ }
+}
+
+static bool EncodeRSAPublicKey(const std::vector<uint8_t>& modulus_n,
+ const std::vector<uint8_t>& public_exponent_e,
+ std::vector<uint8_t>* public_key_info) {
+ // The public key is specified as the following ASN.1 structure:
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ //
+ // The algorithm is specified as the following ASN.1 structure:
+ // AlgorithmIdentifier ::= SEQUENCE {
+ // algorithm OBJECT IDENTIFIER,
+ // parameters ANY DEFINED BY algorithm OPTIONAL }
+ //
+ // An RSA public key is specified as the following ASN.1 structure:
+ // RSAPublicKey ::= SEQUENCE {
+ // modulus INTEGER, -- n
+ // publicExponent INTEGER -- e
+ // }
+ static const uint8_t kIntegerTag = 0x02;
+ static const uint8_t kBitStringTag = 0x03;
+ static const uint8_t kSequenceTag = 0x30;
+ public_key_info->clear();
+
+ // Encode the public exponent e as an INTEGER.
+ public_key_info->insert(public_key_info->begin(),
+ public_exponent_e.begin(),
+ public_exponent_e.end());
+ PrependASN1Length(public_key_info, public_exponent_e.size());
+ public_key_info->insert(public_key_info->begin(), kIntegerTag);
+
+ // Encode the modulus n as an INTEGER.
+ public_key_info->insert(public_key_info->begin(),
+ modulus_n.begin(), modulus_n.end());
+ size_t modulus_size = modulus_n.size();
+ if (modulus_n[0] & 0x80) {
+ public_key_info->insert(public_key_info->begin(), 0x00);
+ modulus_size++;
+ }
+ PrependASN1Length(public_key_info, modulus_size);
+ public_key_info->insert(public_key_info->begin(), kIntegerTag);
+
+ // Encode the RSAPublicKey SEQUENCE.
+ PrependASN1Length(public_key_info, public_key_info->size());
+ public_key_info->insert(public_key_info->begin(), kSequenceTag);
+
+ // Encode the BIT STRING.
+ // Number of unused bits.
+ public_key_info->insert(public_key_info->begin(), 0x00);
+ PrependASN1Length(public_key_info, public_key_info->size());
+ public_key_info->insert(public_key_info->begin(), kBitStringTag);
+
+ // Encode the AlgorithmIdentifier.
+ static const uint8_t algorithm[] = {
+ 0x30, 0x0d, // a SEQUENCE of length 13
+ 0x06, 0x09, // an OBJECT IDENTIFIER of length 9
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+ };
+ public_key_info->insert(public_key_info->begin(),
+ algorithm, algorithm + sizeof(algorithm));
+
+ // Encode the outermost SEQUENCE.
+ PrependASN1Length(public_key_info, public_key_info->size());
+ public_key_info->insert(public_key_info->begin(), kSequenceTag);
+
+ return true;
+}
+
+TEST(SignatureVerifierTest, VerifyRSAPSS) {
+ for (unsigned int i = 0; i < arraysize(pss_test); i++) {
+ SCOPED_TRACE(i);
+ std::vector<uint8_t> modulus_n;
+ std::vector<uint8_t> public_exponent_e;
+ ASSERT_TRUE(DecodeTestInput(pss_test[i].modulus_n, &modulus_n));
+ ASSERT_TRUE(DecodeTestInput(pss_test[i].public_exponent_e,
+ &public_exponent_e));
+ std::vector<uint8_t> public_key_info;
+ ASSERT_TRUE(EncodeRSAPublicKey(modulus_n, public_exponent_e,
+ &public_key_info));
+
+ for (unsigned int j = 0; j < arraysize(pss_test[i].example); j++) {
+ SCOPED_TRACE(j);
+ std::vector<uint8_t> message;
+ std::vector<uint8_t> salt;
+ std::vector<uint8_t> signature;
+ ASSERT_TRUE(DecodeTestInput(pss_test[i].example[j].message, &message));
+ ASSERT_TRUE(DecodeTestInput(pss_test[i].example[j].salt, &salt));
+ ASSERT_TRUE(DecodeTestInput(pss_test[i].example[j].signature,
+ &signature));
+
+ crypto::SignatureVerifier verifier;
+ bool ok;
+
+ // Positive test.
+ ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+ crypto::SignatureVerifier::SHA1,
+ salt.size(),
+ &signature[0], signature.size(),
+ &public_key_info[0],
+ public_key_info.size());
+ ASSERT_TRUE(ok);
+ verifier.VerifyUpdate(&message[0], message.size());
+ ok = verifier.VerifyFinal();
+ EXPECT_TRUE(ok);
+
+ // Modify the first byte of the message.
+ ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+ crypto::SignatureVerifier::SHA1,
+ salt.size(),
+ &signature[0], signature.size(),
+ &public_key_info[0],
+ public_key_info.size());
+ ASSERT_TRUE(ok);
+ message[0] += 1;
+ verifier.VerifyUpdate(&message[0], message.size());
+ message[0] -= 1;
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+
+ // Truncate the message.
+ ASSERT_FALSE(message.empty());
+ ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+ crypto::SignatureVerifier::SHA1,
+ salt.size(),
+ &signature[0], signature.size(),
+ &public_key_info[0],
+ public_key_info.size());
+ ASSERT_TRUE(ok);
+ verifier.VerifyUpdate(&message[0], message.size() - 1);
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+
+ // Corrupt the signature.
+ signature[0] += 1;
+ ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+ crypto::SignatureVerifier::SHA1,
+ salt.size(),
+ &signature[0], signature.size(),
+ &public_key_info[0],
+ public_key_info.size());
+ signature[0] -= 1;
+ ASSERT_TRUE(ok);
+ verifier.VerifyUpdate(&message[0], message.size());
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+ }
+ }
+}
diff --git a/crypto/symmetric_key.cc b/crypto/symmetric_key.cc
new file mode 100644
index 0000000..69283f8
--- /dev/null
+++ b/crypto/symmetric_key.cc
@@ -0,0 +1,106 @@
+// Copyright 2011 The Chromium Authors
+// 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 <openssl/evp.h>
+#include <openssl/rand.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "crypto/openssl_util.h"
+
+namespace crypto {
+
+SymmetricKey::~SymmetricKey() {
+ std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key.
+}
+
+// static
+SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
+ size_t key_size_in_bits) {
+ DCHECK_EQ(AES, algorithm);
+
+ // 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;
+
+ size_t key_size_in_bytes = key_size_in_bits / 8;
+ DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
+
+ if (key_size_in_bytes == 0)
+ return NULL;
+
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ std::unique_ptr<SymmetricKey> key(new SymmetricKey);
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(
+ base::WriteInto(&key->key_, key_size_in_bytes + 1));
+
+ int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes));
+ return rv == 1 ? key.release() : NULL;
+}
+
+// static
+SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
+ const std::string& password,
+ const std::string& salt,
+ size_t iterations,
+ size_t key_size_in_bits) {
+ DCHECK(algorithm == AES || algorithm == HMAC_SHA1);
+
+ 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;
+ }
+
+ size_t key_size_in_bytes = key_size_in_bits / 8;
+ DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
+
+ if (key_size_in_bytes == 0)
+ return NULL;
+
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ std::unique_ptr<SymmetricKey> key(new SymmetricKey);
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(
+ base::WriteInto(&key->key_, key_size_in_bytes + 1));
+ int rv = PKCS5_PBKDF2_HMAC_SHA1(
+ password.data(), password.length(),
+ reinterpret_cast<const uint8_t*>(salt.data()), salt.length(),
+ static_cast<unsigned>(iterations),
+ key_size_in_bytes, key_data);
+ return rv == 1 ? key.release() : NULL;
+}
+
+// static
+SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
+ const std::string& raw_key) {
+ 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;
+ }
+
+ std::unique_ptr<SymmetricKey> key(new SymmetricKey);
+ key->key_ = raw_key;
+ return key.release();
+}
+
+bool SymmetricKey::GetRawKey(std::string* raw_key) {
+ *raw_key = key_;
+ return true;
+}
+
+} // namespace crypto
diff --git a/crypto/symmetric_key.h b/crypto/symmetric_key.h
new file mode 100644
index 0000000..4508619
--- /dev/null
+++ b/crypto/symmetric_key.h
@@ -0,0 +1,104 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_SYMMETRIC_KEY_H_
+#define CRYPTO_SYMMETRIC_KEY_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined(NACL_WIN64)
+// 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 {
+
+// Wraps a platform-specific symmetric key and allows it to be held in a
+// scoped_ptr.
+class CRYPTO_EXPORT SymmetricKey {
+ public:
+ // Defines the algorithm that a key will be used with. See also
+ // classs Encrptor.
+ enum Algorithm {
+ AES,
+ HMAC_SHA1,
+ };
+
+ SymmetricKey(const SymmetricKey&) = delete;
+ SymmetricKey& operator=(const SymmetricKey&) = delete;
+
+ virtual ~SymmetricKey();
+
+ // Generates a random key suitable to be used with |algorithm| and of
+ // |key_size_in_bits| bits. |key_size_in_bits| must be a multiple of 8.
+ // The caller is responsible for deleting the returned SymmetricKey.
+ static SymmetricKey* GenerateRandomKey(Algorithm algorithm,
+ size_t key_size_in_bits);
+
+ // Derives a key from the supplied password and salt using PBKDF2, suitable
+ // for use with specified |algorithm|. Note |algorithm| is not the algorithm
+ // used to derive the key from the password. |key_size_in_bits| must be a
+ // multiple of 8. The caller is responsible for deleting the returned
+ // SymmetricKey.
+ static SymmetricKey* DeriveKeyFromPassword(Algorithm algorithm,
+ const std::string& password,
+ const std::string& salt,
+ size_t iterations,
+ size_t key_size_in_bits);
+
+ // Imports an array of key bytes in |raw_key|. This key may have been
+ // generated by GenerateRandomKey or DeriveKeyFromPassword and exported with
+ // GetRawKey, or via another compatible method. The key must be of suitable
+ // size for use with |algorithm|. The caller owns the returned SymmetricKey.
+ static SymmetricKey* Import(Algorithm algorithm, const std::string& raw_key);
+
+#if defined(NACL_WIN64)
+ HCRYPTKEY key() const { return key_.get(); }
+#elif defined(USE_OPENSSL)
+ 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.
+ // Warning: |raw_key| holds the raw key as bytes and thus must be handled
+ // carefully.
+ bool GetRawKey(std::string* raw_key);
+
+ private:
+#if defined(NACL_WIN64)
+ SymmetricKey(HCRYPTPROV provider, HCRYPTKEY key,
+ const void* key_data, size_t key_size_in_bytes);
+
+ ScopedHCRYPTPROV provider_;
+ ScopedHCRYPTKEY key_;
+
+ // Contains the raw key, if it is known during initialization and when it
+ // is likely that the associated |provider_| will be unable to export the
+ // |key_|. This is the case of HMAC keys when the key size exceeds 16 bytes
+ // when using the default RSA provider.
+ // 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)
+ SymmetricKey() {}
+ std::string key_;
+#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
+ explicit SymmetricKey(PK11SymKey* key);
+ ScopedPK11SymKey key_;
+#endif
+};
+
+} // namespace crypto
+
+#endif // CRYPTO_SYMMETRIC_KEY_H_
diff --git a/crypto/symmetric_key_nss.cc b/crypto/symmetric_key_nss.cc
new file mode 100644
index 0000000..ccdde5b
--- /dev/null
+++ b/crypto/symmetric_key_nss.cc
@@ -0,0 +1,151 @@
+// Copyright 2012 The Chromium Authors
+// 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/symmetric_key_unittest.cc b/crypto/symmetric_key_unittest.cc
new file mode 100644
index 0000000..4ce3f30
--- /dev/null
+++ b/crypto/symmetric_key_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright 2011 The Chromium Authors
+// 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 <memory>
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SymmetricKeyTest, GenerateRandomKey) {
+ std::unique_ptr<crypto::SymmetricKey> key(
+ crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
+ ASSERT_TRUE(NULL != key.get());
+ std::string raw_key;
+ EXPECT_TRUE(key->GetRawKey(&raw_key));
+ EXPECT_EQ(32U, raw_key.size());
+
+ // Do it again and check that the keys are different.
+ // (Note: this has a one-in-10^77 chance of failure!)
+ std::unique_ptr<crypto::SymmetricKey> key2(
+ crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
+ ASSERT_TRUE(NULL != key2.get());
+ std::string raw_key2;
+ EXPECT_TRUE(key2->GetRawKey(&raw_key2));
+ EXPECT_EQ(32U, raw_key2.size());
+ EXPECT_NE(raw_key, raw_key2);
+}
+
+TEST(SymmetricKeyTest, ImportGeneratedKey) {
+ std::unique_ptr<crypto::SymmetricKey> key1(
+ crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
+ ASSERT_TRUE(NULL != key1.get());
+ std::string raw_key1;
+ EXPECT_TRUE(key1->GetRawKey(&raw_key1));
+
+ std::unique_ptr<crypto::SymmetricKey> key2(
+ crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key1));
+ ASSERT_TRUE(NULL != key2.get());
+
+ std::string raw_key2;
+ EXPECT_TRUE(key2->GetRawKey(&raw_key2));
+
+ EXPECT_EQ(raw_key1, raw_key2);
+}
+
+TEST(SymmetricKeyTest, ImportDerivedKey) {
+ std::unique_ptr<crypto::SymmetricKey> key1(
+ crypto::SymmetricKey::DeriveKeyFromPassword(
+ crypto::SymmetricKey::HMAC_SHA1, "password", "somesalt", 1024, 160));
+ ASSERT_TRUE(NULL != key1.get());
+ std::string raw_key1;
+ EXPECT_TRUE(key1->GetRawKey(&raw_key1));
+
+ std::unique_ptr<crypto::SymmetricKey> key2(
+ crypto::SymmetricKey::Import(crypto::SymmetricKey::HMAC_SHA1, raw_key1));
+ ASSERT_TRUE(NULL != key2.get());
+
+ std::string raw_key2;
+ EXPECT_TRUE(key2->GetRawKey(&raw_key2));
+
+ EXPECT_EQ(raw_key1, raw_key2);
+}
+
+struct PBKDF2TestVector {
+ crypto::SymmetricKey::Algorithm algorithm;
+ const char* password;
+ const char* salt;
+ unsigned int rounds;
+ unsigned int key_size_in_bits;
+ const char* expected; // ASCII encoded hex bytes
+};
+
+class SymmetricKeyDeriveKeyFromPasswordTest
+ : public testing::TestWithParam<PBKDF2TestVector> {
+};
+
+TEST_P(SymmetricKeyDeriveKeyFromPasswordTest, DeriveKeyFromPassword) {
+ PBKDF2TestVector test_data(GetParam());
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The OS X crypto libraries have minimum salt and iteration requirements
+ // so some of the tests below will cause them to barf. Skip these.
+ if (strlen(test_data.salt) < 8 || test_data.rounds < 1000) {
+ VLOG(1) << "Skipped test vector for " << test_data.expected;
+ return;
+ }
+#endif // OS_MACOSX
+
+ std::unique_ptr<crypto::SymmetricKey> key(
+ crypto::SymmetricKey::DeriveKeyFromPassword(
+ test_data.algorithm, test_data.password, test_data.salt,
+ test_data.rounds, test_data.key_size_in_bits));
+ ASSERT_TRUE(NULL != key.get());
+
+ std::string raw_key;
+ key->GetRawKey(&raw_key);
+ EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size());
+ EXPECT_EQ(test_data.expected,
+ base::ToLowerASCII(base::HexEncode(raw_key.data(),
+ raw_key.size())));
+}
+
+static const PBKDF2TestVector kTestVectors[] = {
+ // These tests come from
+ // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "salt",
+ 1,
+ 160,
+ "0c60c80f961f0e71f3a9b524af6012062fe037a6",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "salt",
+ 2,
+ 160,
+ "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "salt",
+ 4096,
+ 160,
+ "4b007901b765489abead49d926f721d065a429c1",
+ },
+ // This test takes over 30s to run on the trybots.
+#if 0
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "salt",
+ 16777216,
+ 160,
+ "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984",
+ },
+#endif
+
+ // These tests come from RFC 3962, via BSD source code at
+ // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "ATHENA.MIT.EDUraeburn",
+ 1,
+ 160,
+ "cdedb5281bb2f801565a1122b25635150ad1f7a0",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "ATHENA.MIT.EDUraeburn",
+ 2,
+ 160,
+ "01dbee7f4a9e243e988b62c73cda935da05378b9",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "ATHENA.MIT.EDUraeburn",
+ 1200,
+ 160,
+ "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddb",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "password",
+ "\022" "4VxxV4\022", /* 0x1234567878563412 */
+ 5,
+ 160,
+ "d1daa78615f287e6a1c8b120d7062a493f98d203",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase equals block size",
+ 1200,
+ 160,
+ "139c30c0966bc32ba55fdbf212530ac9c5ec59f1",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase exceeds block size",
+ 1200,
+ 160,
+ "9ccad6d468770cd51b10e6a68721be611a8b4d28",
+ },
+ {
+ crypto::SymmetricKey::HMAC_SHA1,
+ "\360\235\204\236", /* g-clef (0xf09d849e) */
+ "EXAMPLE.COMpianist",
+ 50,
+ 160,
+ "6b9cf26d45455a43a5b8bb276a403b39e7fe37a0",
+ },
+
+ // Regression tests for AES keys, derived from the Linux NSS implementation.
+ {
+ crypto::SymmetricKey::AES,
+ "A test password",
+ "saltsalt",
+ 1,
+ 256,
+ "44899a7777f0e6e8b752f875f02044b8ac593de146de896f2e8a816e315a36de",
+ },
+ {
+ crypto::SymmetricKey::AES,
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase exceeds block size",
+ 20,
+ 256,
+ "e0739745dc28b8721ba402e05214d2ac1eab54cf72bee1fba388297a09eb493c",
+ },
+};
+
+INSTANTIATE_TEST_CASE_P(, SymmetricKeyDeriveKeyFromPasswordTest,
+ testing::ValuesIn(kTestVectors));
diff --git a/crypto/third_party/nss/chromium-blapi.h b/crypto/third_party/nss/chromium-blapi.h
new file mode 100644
index 0000000..2ca772e
--- /dev/null
+++ b/crypto/third_party/nss/chromium-blapi.h
@@ -0,0 +1,101 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * ***** 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 ***** */
+/* $Id: blapi.h,v 1.27 2007/11/09 18:49:32 wtc%google.com Exp $ */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_
+
+#include "crypto/third_party/nss/chromium-blapit.h"
+
+/******************************************/
+
+extern SHA256Context *SHA256_NewContext(void);
+extern void SHA256_DestroyContext(SHA256Context *cx, PRBool freeit);
+extern void SHA256_Begin(SHA256Context *cx);
+extern void SHA256_Update(SHA256Context *cx, const unsigned char *input,
+ unsigned int inputLen);
+extern void SHA256_End(SHA256Context *cx, unsigned char *digest,
+ unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
+ unsigned int src_length);
+extern SECStatus SHA256_Hash(unsigned char *dest, const char *src);
+extern void SHA256_TraceState(SHA256Context *cx);
+extern unsigned int SHA256_FlattenSize(SHA256Context *cx);
+extern SECStatus SHA256_Flatten(SHA256Context *cx,unsigned char *space);
+extern SHA256Context * SHA256_Resurrect(unsigned char *space, void *arg);
+extern void SHA256_Clone(SHA256Context *dest, SHA256Context *src);
+
+/******************************************/
+
+extern SHA512Context *SHA512_NewContext(void);
+extern void SHA512_DestroyContext(SHA512Context *cx, PRBool freeit);
+extern void SHA512_Begin(SHA512Context *cx);
+extern void SHA512_Update(SHA512Context *cx, const unsigned char *input,
+ unsigned int inputLen);
+extern void SHA512_End(SHA512Context *cx, unsigned char *digest,
+ unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
+ unsigned int src_length);
+extern SECStatus SHA512_Hash(unsigned char *dest, const char *src);
+extern void SHA512_TraceState(SHA512Context *cx);
+extern unsigned int SHA512_FlattenSize(SHA512Context *cx);
+extern SECStatus SHA512_Flatten(SHA512Context *cx,unsigned char *space);
+extern SHA512Context * SHA512_Resurrect(unsigned char *space, void *arg);
+extern void SHA512_Clone(SHA512Context *dest, SHA512Context *src);
+
+/******************************************/
+
+extern SHA384Context *SHA384_NewContext(void);
+extern void SHA384_DestroyContext(SHA384Context *cx, PRBool freeit);
+extern void SHA384_Begin(SHA384Context *cx);
+extern void SHA384_Update(SHA384Context *cx, const unsigned char *input,
+ unsigned int inputLen);
+extern void SHA384_End(SHA384Context *cx, unsigned char *digest,
+ unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
+ unsigned int src_length);
+extern SECStatus SHA384_Hash(unsigned char *dest, const char *src);
+extern void SHA384_TraceState(SHA384Context *cx);
+extern unsigned int SHA384_FlattenSize(SHA384Context *cx);
+extern SECStatus SHA384_Flatten(SHA384Context *cx,unsigned char *space);
+extern SHA384Context * SHA384_Resurrect(unsigned char *space, void *arg);
+extern void SHA384_Clone(SHA384Context *dest, SHA384Context *src);
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_ */
diff --git a/crypto/third_party/nss/chromium-blapit.h b/crypto/third_party/nss/chromium-blapit.h
new file mode 100644
index 0000000..938547a
--- /dev/null
+++ b/crypto/third_party/nss/chromium-blapit.h
@@ -0,0 +1,91 @@
+/*
+ * blapit.h - public data structures for the crypto library
+ *
+ * ***** 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> 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 ***** */
+/* $Id: blapit.h,v 1.20 2007/02/28 19:47:37 rrelyea%redhat.com Exp $ */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_
+
+#include "crypto/third_party/nss/chromium-prtypes.h"
+
+/*
+** A status code. Status's are used by procedures that return status
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong. Correct testing of status codes:
+**
+** SECStatus rv;
+** rv = some_function (some_argument);
+** if (rv != SECSuccess)
+** do_an_error_thing();
+**
+*/
+typedef enum _SECStatus {
+ SECWouldBlock = -2,
+ SECFailure = -1,
+ SECSuccess = 0
+} SECStatus;
+
+#define SHA256_LENGTH 32 /* bytes */
+#define SHA384_LENGTH 48 /* bytes */
+#define SHA512_LENGTH 64 /* bytes */
+#define HASH_LENGTH_MAX SHA512_LENGTH
+
+/*
+ * Input block size for each hash algorithm.
+ */
+
+#define SHA256_BLOCK_LENGTH 64 /* bytes */
+#define SHA384_BLOCK_LENGTH 128 /* bytes */
+#define SHA512_BLOCK_LENGTH 128 /* bytes */
+#define HASH_BLOCK_LENGTH_MAX SHA512_BLOCK_LENGTH
+
+/***************************************************************************
+** Opaque objects
+*/
+
+struct SHA256ContextStr ;
+struct SHA512ContextStr ;
+
+typedef struct SHA256ContextStr SHA256Context;
+typedef struct SHA512ContextStr SHA512Context;
+/* SHA384Context is really a SHA512ContextStr. This is not a mistake. */
+typedef struct SHA512ContextStr SHA384Context;
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_ */
diff --git a/crypto/third_party/nss/chromium-nss.h b/crypto/third_party/nss/chromium-nss.h
new file mode 100644
index 0000000..437e6bd
--- /dev/null
+++ b/crypto/third_party/nss/chromium-nss.h
@@ -0,0 +1,79 @@
+ /* ***** 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):
+ *
+ * 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 ***** */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
+
+// This file contains some functions we borrowed from NSS.
+
+#include <prtypes.h>
+#include <hasht.h>
+#include <keyhi.h>
+#include <secmod.h>
+
+#include "crypto/crypto_export.h"
+
+extern "C" SECStatus emsa_pss_verify(const unsigned char *mHash,
+ const unsigned char *em,
+ unsigned int emLen,
+ HASH_HashType hashAlg,
+ HASH_HashType maskHashAlg,
+ unsigned int sLen);
+
+// Like PK11_ImportEncryptedPrivateKeyInfo, but hardcoded for EC, and returns
+// the SECKEYPrivateKey.
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=211546
+// When we use NSS 3.13.2 or later,
+// PK11_ImportEncryptedPrivateKeyInfoAndReturnKey can be used instead.
+SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey(
+ PK11SlotInfo* slot,
+ SECKEYEncryptedPrivateKeyInfo* epki,
+ SECItem* password,
+ SECItem* nickname,
+ SECItem* public_value,
+ PRBool permanent,
+ PRBool sensitive,
+ SECKEYPrivateKey** private_key,
+ void* wincx);
+
+// Like SEC_DerSignData.
+CRYPTO_EXPORT SECStatus DerSignData(PLArenaPool *arena,
+ SECItem *result,
+ SECItem *input,
+ SECKEYPrivateKey *key,
+ SECOidTag algo_id);
+
+#endif // CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
diff --git a/crypto/third_party/nss/chromium-prtypes.h b/crypto/third_party/nss/chromium-prtypes.h
new file mode 100644
index 0000000..d5ea8a9
--- /dev/null
+++ b/crypto/third_party/nss/chromium-prtypes.h
@@ -0,0 +1,77 @@
+/* ***** 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) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ***** */
+
+/* Emulates the real prtypes.h. Defines the types and macros that sha512.cc
+ * needs. */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_PRTYPES_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_PRTYPES_H_
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+#define IS_LITTLE_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 1
+#endif
+
+/*
+ * The C language requires that 'long' be at least 32 bits. 2147483647 is the
+ * largest signed 32-bit integer.
+ */
+#if LONG_MAX > 2147483647L
+#define PR_BYTES_PER_LONG 8
+#else
+#define PR_BYTES_PER_LONG 4
+#endif
+
+#define HAVE_LONG_LONG
+
+#if defined(__linux__)
+#define LINUX
+#endif
+
+typedef uint8_t PRUint8;
+typedef uint32_t PRUint32;
+
+typedef int PRBool;
+
+#define PR_MIN(x,y) ((x)<(y)?(x):(y))
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_PRTYPES_H_ */
diff --git a/crypto/third_party/nss/chromium-sha256.h b/crypto/third_party/nss/chromium-sha256.h
new file mode 100644
index 0000000..52815ca
--- /dev/null
+++ b/crypto/third_party/nss/chromium-sha256.h
@@ -0,0 +1,51 @@
+/* ***** 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) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ***** */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_
+
+#include "crypto/third_party/nss/chromium-prtypes.h"
+
+struct SHA256ContextStr {
+ union {
+ PRUint32 w[64]; /* message schedule, input buffer, plus 48 words */
+ PRUint8 b[256];
+ } u;
+ PRUint32 h[8]; /* 8 state variables */
+ PRUint32 sizeHi,sizeLo; /* 64-bit count of hashed bytes. */
+};
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_ */
diff --git a/crypto/third_party/nss/rsawrapr.c b/crypto/third_party/nss/rsawrapr.c
new file mode 100644
index 0000000..73e498f
--- /dev/null
+++ b/crypto/third_party/nss/rsawrapr.c
@@ -0,0 +1,160 @@
+/*
+ * 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/sha512.cc b/crypto/third_party/nss/sha512.cc
new file mode 100644
index 0000000..4698bf2
--- /dev/null
+++ b/crypto/third_party/nss/sha512.cc
@@ -0,0 +1,1390 @@
+/*
+ * sha512.c - implementation of SHA256, SHA384 and SHA512
+ *
+ * ***** 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) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ***** */
+/* $Id: sha512.c,v 1.9 2006/10/13 16:54:04 wtchang%redhat.com Exp $ */
+
+// Prevent manual unrolling in the sha256 code, which reduces the binary code
+// size from ~10k to ~1k. The performance should be reasonable for our use.
+#define NOUNROLL256 1
+
+#include "crypto/third_party/nss/chromium-prtypes.h" /* for PRUintXX */
+#if defined(_X86_) || defined(SHA_NO_LONG_LONG)
+#define NOUNROLL512 1
+#undef HAVE_LONG_LONG
+#endif
+#include "crypto/third_party/nss/chromium-blapi.h"
+#include "crypto/third_party/nss/chromium-sha256.h" /* for struct SHA256ContextStr */
+
+#include <stdlib.h>
+#include <string.h>
+#define PORT_New(type) static_cast<type*>(malloc(sizeof(type)))
+#define PORT_ZFree(ptr, len) do { memset(ptr, 0, len); free(ptr); } while (0)
+#define PORT_Strlen(s) static_cast<unsigned int>(strlen(s))
+#define PORT_Memcpy memcpy
+
+/* ============= Common constants and defines ======================= */
+
+#define W ctx->u.w
+#define B ctx->u.b
+#define H ctx->h
+
+#define SHR(x,n) (x >> n)
+#define SHL(x,n) (x << n)
+#define Ch(x,y,z) ((x & y) ^ (~x & z))
+#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
+
+/* Padding used with all flavors of SHA */
+static const PRUint8 pad[240] = {
+0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ /* compiler will fill the rest in with zeros */
+};
+
+/* ============= SHA256 implemenmtation ================================== */
+
+/* SHA-256 constants, K256. */
+static const PRUint32 K256[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/* SHA-256 initial hash values */
+static const PRUint32 H256[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+#if defined(_MSC_VER) && defined(_X86_)
+#ifndef FORCEINLINE
+#if (_MSC_VER >= 1200)
+#define FORCEINLINE __forceinline
+#else
+#define FORCEINLINE __inline
+#endif
+#endif
+#define FASTCALL __fastcall
+
+static FORCEINLINE PRUint32 FASTCALL
+swap4b(PRUint32 dwd)
+{
+ __asm {
+ mov eax,dwd
+ bswap eax
+ }
+}
+
+#define SHA_HTONL(x) swap4b(x)
+#define BYTESWAP4(x) x = SHA_HTONL(x)
+
+#elif defined(LINUX) && defined(_X86_)
+#undef __OPTIMIZE__
+#define __OPTIMIZE__ 1
+#undef __pentium__
+#define __pentium__ 1
+#include <byteswap.h>
+#define SHA_HTONL(x) bswap_32(x)
+#define BYTESWAP4(x) x = SHA_HTONL(x)
+
+#else /* neither windows nor Linux PC */
+#define SWAP4MASK 0x00FF00FF
+#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \
+ ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK))
+#define BYTESWAP4(x) x = SHA_HTONL(x)
+#endif
+
+#if defined(_MSC_VER) && defined(_X86_)
+#pragma intrinsic (_lrotr, _lrotl)
+#define ROTR32(x,n) _lrotr(x,n)
+#define ROTL32(x,n) _lrotl(x,n)
+#else
+#define ROTR32(x,n) ((x >> n) | (x << ((8 * sizeof x) - n)))
+#define ROTL32(x,n) ((x << n) | (x >> ((8 * sizeof x) - n)))
+#endif
+
+/* Capitol Sigma and lower case sigma functions */
+#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22))
+#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25))
+#define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3))
+#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10))
+
+SHA256Context *
+SHA256_NewContext(void)
+{
+ SHA256Context *ctx = PORT_New(SHA256Context);
+ return ctx;
+}
+
+void
+SHA256_DestroyContext(SHA256Context *ctx, PRBool freeit)
+{
+ if (freeit) {
+ PORT_ZFree(ctx, sizeof *ctx);
+ }
+}
+
+void
+SHA256_Begin(SHA256Context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ memcpy(H, H256, sizeof H256);
+}
+
+static void
+SHA256_Compress(SHA256Context *ctx)
+{
+ {
+ PRUint32 t1, t2;
+
+#if defined(IS_LITTLE_ENDIAN)
+ BYTESWAP4(W[0]);
+ BYTESWAP4(W[1]);
+ BYTESWAP4(W[2]);
+ BYTESWAP4(W[3]);
+ BYTESWAP4(W[4]);
+ BYTESWAP4(W[5]);
+ BYTESWAP4(W[6]);
+ BYTESWAP4(W[7]);
+ BYTESWAP4(W[8]);
+ BYTESWAP4(W[9]);
+ BYTESWAP4(W[10]);
+ BYTESWAP4(W[11]);
+ BYTESWAP4(W[12]);
+ BYTESWAP4(W[13]);
+ BYTESWAP4(W[14]);
+ BYTESWAP4(W[15]);
+#endif
+
+#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
+
+ /* prepare the "message schedule" */
+#ifdef NOUNROLL256
+ {
+ int t;
+ for (t = 16; t < 64; ++t) {
+ INITW(t);
+ }
+ }
+#else
+ INITW(16);
+ INITW(17);
+ INITW(18);
+ INITW(19);
+
+ INITW(20);
+ INITW(21);
+ INITW(22);
+ INITW(23);
+ INITW(24);
+ INITW(25);
+ INITW(26);
+ INITW(27);
+ INITW(28);
+ INITW(29);
+
+ INITW(30);
+ INITW(31);
+ INITW(32);
+ INITW(33);
+ INITW(34);
+ INITW(35);
+ INITW(36);
+ INITW(37);
+ INITW(38);
+ INITW(39);
+
+ INITW(40);
+ INITW(41);
+ INITW(42);
+ INITW(43);
+ INITW(44);
+ INITW(45);
+ INITW(46);
+ INITW(47);
+ INITW(48);
+ INITW(49);
+
+ INITW(50);
+ INITW(51);
+ INITW(52);
+ INITW(53);
+ INITW(54);
+ INITW(55);
+ INITW(56);
+ INITW(57);
+ INITW(58);
+ INITW(59);
+
+ INITW(60);
+ INITW(61);
+ INITW(62);
+ INITW(63);
+
+#endif
+#undef INITW
+ }
+ {
+ PRUint32 a, b, c, d, e, f, g, h;
+
+ a = H[0];
+ b = H[1];
+ c = H[2];
+ d = H[3];
+ e = H[4];
+ f = H[5];
+ g = H[6];
+ h = H[7];
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+ h += S1(e) + Ch(e,f,g) + K256[n] + W[n]; \
+ d += h; \
+ h += S0(a) + Maj(a,b,c);
+
+#ifdef NOUNROLL256
+ {
+ int t;
+ for (t = 0; t < 64; t+= 8) {
+ ROUND(t+0,a,b,c,d,e,f,g,h)
+ ROUND(t+1,h,a,b,c,d,e,f,g)
+ ROUND(t+2,g,h,a,b,c,d,e,f)
+ ROUND(t+3,f,g,h,a,b,c,d,e)
+ ROUND(t+4,e,f,g,h,a,b,c,d)
+ ROUND(t+5,d,e,f,g,h,a,b,c)
+ ROUND(t+6,c,d,e,f,g,h,a,b)
+ ROUND(t+7,b,c,d,e,f,g,h,a)
+ }
+ }
+#else
+ ROUND( 0,a,b,c,d,e,f,g,h)
+ ROUND( 1,h,a,b,c,d,e,f,g)
+ ROUND( 2,g,h,a,b,c,d,e,f)
+ ROUND( 3,f,g,h,a,b,c,d,e)
+ ROUND( 4,e,f,g,h,a,b,c,d)
+ ROUND( 5,d,e,f,g,h,a,b,c)
+ ROUND( 6,c,d,e,f,g,h,a,b)
+ ROUND( 7,b,c,d,e,f,g,h,a)
+
+ ROUND( 8,a,b,c,d,e,f,g,h)
+ ROUND( 9,h,a,b,c,d,e,f,g)
+ ROUND(10,g,h,a,b,c,d,e,f)
+ ROUND(11,f,g,h,a,b,c,d,e)
+ ROUND(12,e,f,g,h,a,b,c,d)
+ ROUND(13,d,e,f,g,h,a,b,c)
+ ROUND(14,c,d,e,f,g,h,a,b)
+ ROUND(15,b,c,d,e,f,g,h,a)
+
+ ROUND(16,a,b,c,d,e,f,g,h)
+ ROUND(17,h,a,b,c,d,e,f,g)
+ ROUND(18,g,h,a,b,c,d,e,f)
+ ROUND(19,f,g,h,a,b,c,d,e)
+ ROUND(20,e,f,g,h,a,b,c,d)
+ ROUND(21,d,e,f,g,h,a,b,c)
+ ROUND(22,c,d,e,f,g,h,a,b)
+ ROUND(23,b,c,d,e,f,g,h,a)
+
+ ROUND(24,a,b,c,d,e,f,g,h)
+ ROUND(25,h,a,b,c,d,e,f,g)
+ ROUND(26,g,h,a,b,c,d,e,f)
+ ROUND(27,f,g,h,a,b,c,d,e)
+ ROUND(28,e,f,g,h,a,b,c,d)
+ ROUND(29,d,e,f,g,h,a,b,c)
+ ROUND(30,c,d,e,f,g,h,a,b)
+ ROUND(31,b,c,d,e,f,g,h,a)
+
+ ROUND(32,a,b,c,d,e,f,g,h)
+ ROUND(33,h,a,b,c,d,e,f,g)
+ ROUND(34,g,h,a,b,c,d,e,f)
+ ROUND(35,f,g,h,a,b,c,d,e)
+ ROUND(36,e,f,g,h,a,b,c,d)
+ ROUND(37,d,e,f,g,h,a,b,c)
+ ROUND(38,c,d,e,f,g,h,a,b)
+ ROUND(39,b,c,d,e,f,g,h,a)
+
+ ROUND(40,a,b,c,d,e,f,g,h)
+ ROUND(41,h,a,b,c,d,e,f,g)
+ ROUND(42,g,h,a,b,c,d,e,f)
+ ROUND(43,f,g,h,a,b,c,d,e)
+ ROUND(44,e,f,g,h,a,b,c,d)
+ ROUND(45,d,e,f,g,h,a,b,c)
+ ROUND(46,c,d,e,f,g,h,a,b)
+ ROUND(47,b,c,d,e,f,g,h,a)
+
+ ROUND(48,a,b,c,d,e,f,g,h)
+ ROUND(49,h,a,b,c,d,e,f,g)
+ ROUND(50,g,h,a,b,c,d,e,f)
+ ROUND(51,f,g,h,a,b,c,d,e)
+ ROUND(52,e,f,g,h,a,b,c,d)
+ ROUND(53,d,e,f,g,h,a,b,c)
+ ROUND(54,c,d,e,f,g,h,a,b)
+ ROUND(55,b,c,d,e,f,g,h,a)
+
+ ROUND(56,a,b,c,d,e,f,g,h)
+ ROUND(57,h,a,b,c,d,e,f,g)
+ ROUND(58,g,h,a,b,c,d,e,f)
+ ROUND(59,f,g,h,a,b,c,d,e)
+ ROUND(60,e,f,g,h,a,b,c,d)
+ ROUND(61,d,e,f,g,h,a,b,c)
+ ROUND(62,c,d,e,f,g,h,a,b)
+ ROUND(63,b,c,d,e,f,g,h,a)
+#endif
+
+ H[0] += a;
+ H[1] += b;
+ H[2] += c;
+ H[3] += d;
+ H[4] += e;
+ H[5] += f;
+ H[6] += g;
+ H[7] += h;
+ }
+#undef ROUND
+}
+
+#undef s0
+#undef s1
+#undef S0
+#undef S1
+
+void
+SHA256_Update(SHA256Context *ctx, const unsigned char *input,
+ unsigned int inputLen)
+{
+ unsigned int inBuf = ctx->sizeLo & 0x3f;
+ if (!inputLen)
+ return;
+
+ /* Add inputLen into the count of bytes processed, before processing */
+ if ((ctx->sizeLo += inputLen) < inputLen)
+ ctx->sizeHi++;
+
+ /* if data already in buffer, attemp to fill rest of buffer */
+ if (inBuf) {
+ unsigned int todo = SHA256_BLOCK_LENGTH - inBuf;
+ if (inputLen < todo)
+ todo = inputLen;
+ memcpy(B + inBuf, input, todo);
+ input += todo;
+ inputLen -= todo;
+ if (inBuf + todo == SHA256_BLOCK_LENGTH)
+ SHA256_Compress(ctx);
+ }
+
+ /* if enough data to fill one or more whole buffers, process them. */
+ while (inputLen >= SHA256_BLOCK_LENGTH) {
+ memcpy(B, input, SHA256_BLOCK_LENGTH);
+ input += SHA256_BLOCK_LENGTH;
+ inputLen -= SHA256_BLOCK_LENGTH;
+ SHA256_Compress(ctx);
+ }
+ /* if data left over, fill it into buffer */
+ if (inputLen)
+ memcpy(B, input, inputLen);
+}
+
+void
+SHA256_End(SHA256Context *ctx, unsigned char *digest,
+ unsigned int *digestLen, unsigned int maxDigestLen)
+{
+ unsigned int inBuf = ctx->sizeLo & 0x3f;
+ unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf);
+ PRUint32 hi, lo;
+#ifdef SWAP4MASK
+ PRUint32 t1;
+#endif
+
+ hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29);
+ lo = (ctx->sizeLo << 3);
+
+ SHA256_Update(ctx, pad, padLen);
+
+#if defined(IS_LITTLE_ENDIAN)
+ W[14] = SHA_HTONL(hi);
+ W[15] = SHA_HTONL(lo);
+#else
+ W[14] = hi;
+ W[15] = lo;
+#endif
+ SHA256_Compress(ctx);
+
+ /* now output the answer */
+#if defined(IS_LITTLE_ENDIAN)
+ BYTESWAP4(H[0]);
+ BYTESWAP4(H[1]);
+ BYTESWAP4(H[2]);
+ BYTESWAP4(H[3]);
+ BYTESWAP4(H[4]);
+ BYTESWAP4(H[5]);
+ BYTESWAP4(H[6]);
+ BYTESWAP4(H[7]);
+#endif
+ padLen = PR_MIN(SHA256_LENGTH, maxDigestLen);
+ memcpy(digest, H, padLen);
+ if (digestLen)
+ *digestLen = padLen;
+}
+
+void SHA256_Clone(SHA256Context* dest, SHA256Context* src)
+{
+ memcpy(dest, src, sizeof *dest);
+}
+
+/* Comment out unused code, mostly the SHA384 and SHA512 implementations. */
+#if 0
+SECStatus
+SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
+ unsigned int src_length)
+{
+ SHA256Context ctx;
+ unsigned int outLen;
+
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx, src, src_length);
+ SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH);
+
+ return SECSuccess;
+}
+
+
+SECStatus
+SHA256_Hash(unsigned char *dest, const char *src)
+{
+ return SHA256_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+
+void SHA256_TraceState(SHA256Context *ctx) { }
+
+unsigned int
+SHA256_FlattenSize(SHA256Context *ctx)
+{
+ return sizeof *ctx;
+}
+
+SECStatus
+SHA256_Flatten(SHA256Context *ctx,unsigned char *space)
+{
+ PORT_Memcpy(space, ctx, sizeof *ctx);
+ return SECSuccess;
+}
+
+SHA256Context *
+SHA256_Resurrect(unsigned char *space, void *arg)
+{
+ SHA256Context *ctx = SHA256_NewContext();
+ if (ctx)
+ PORT_Memcpy(ctx, space, sizeof *ctx);
+ return ctx;
+}
+
+/* ======= SHA512 and SHA384 common constants and defines ================= */
+
+/* common #defines for SHA512 and SHA384 */
+#if defined(HAVE_LONG_LONG)
+#define ROTR64(x,n) ((x >> n) | (x << (64 - n)))
+#define ROTL64(x,n) ((x << n) | (x >> (64 - n)))
+
+#define S0(x) (ROTR64(x,28) ^ ROTR64(x,34) ^ ROTR64(x,39))
+#define S1(x) (ROTR64(x,14) ^ ROTR64(x,18) ^ ROTR64(x,41))
+#define s0(x) (t1 = x, ROTR64(t1, 1) ^ ROTR64(t1, 8) ^ SHR(t1,7))
+#define s1(x) (t2 = x, ROTR64(t2,19) ^ ROTR64(t2,61) ^ SHR(t2,6))
+
+#if PR_BYTES_PER_LONG == 8
+#define ULLC(hi,lo) 0x ## hi ## lo ## UL
+#elif defined(_MSC_VER)
+#define ULLC(hi,lo) 0x ## hi ## lo ## ui64
+#else
+#define ULLC(hi,lo) 0x ## hi ## lo ## ULL
+#endif
+
+#define SHA_MASK16 ULLC(0000FFFF,0000FFFF)
+#define SHA_MASK8 ULLC(00FF00FF,00FF00FF)
+#define SHA_HTONLL(x) (t1 = x, \
+ t1 = ((t1 & SHA_MASK8 ) << 8) | ((t1 >> 8) & SHA_MASK8 ), \
+ t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16), \
+ (t1 >> 32) | (t1 << 32))
+#define BYTESWAP8(x) x = SHA_HTONLL(x)
+
+#else /* no long long */
+
+#if defined(IS_LITTLE_ENDIAN)
+#define ULLC(hi,lo) { 0x ## lo ## U, 0x ## hi ## U }
+#else
+#define ULLC(hi,lo) { 0x ## hi ## U, 0x ## lo ## U }
+#endif
+
+#define SHA_HTONLL(x) ( BYTESWAP4(x.lo), BYTESWAP4(x.hi), \
+ x.hi ^= x.lo ^= x.hi ^= x.lo, x)
+#define BYTESWAP8(x) do { PRUint32 tmp; BYTESWAP4(x.lo); BYTESWAP4(x.hi); \
+ tmp = x.lo; x.lo = x.hi; x.hi = tmp; } while (0)
+#endif
+
+/* SHA-384 and SHA-512 constants, K512. */
+static const PRUint64 K512[80] = {
+#if PR_BYTES_PER_LONG == 8
+ 0x428a2f98d728ae22UL , 0x7137449123ef65cdUL ,
+ 0xb5c0fbcfec4d3b2fUL , 0xe9b5dba58189dbbcUL ,
+ 0x3956c25bf348b538UL , 0x59f111f1b605d019UL ,
+ 0x923f82a4af194f9bUL , 0xab1c5ed5da6d8118UL ,
+ 0xd807aa98a3030242UL , 0x12835b0145706fbeUL ,
+ 0x243185be4ee4b28cUL , 0x550c7dc3d5ffb4e2UL ,
+ 0x72be5d74f27b896fUL , 0x80deb1fe3b1696b1UL ,
+ 0x9bdc06a725c71235UL , 0xc19bf174cf692694UL ,
+ 0xe49b69c19ef14ad2UL , 0xefbe4786384f25e3UL ,
+ 0x0fc19dc68b8cd5b5UL , 0x240ca1cc77ac9c65UL ,
+ 0x2de92c6f592b0275UL , 0x4a7484aa6ea6e483UL ,
+ 0x5cb0a9dcbd41fbd4UL , 0x76f988da831153b5UL ,
+ 0x983e5152ee66dfabUL , 0xa831c66d2db43210UL ,
+ 0xb00327c898fb213fUL , 0xbf597fc7beef0ee4UL ,
+ 0xc6e00bf33da88fc2UL , 0xd5a79147930aa725UL ,
+ 0x06ca6351e003826fUL , 0x142929670a0e6e70UL ,
+ 0x27b70a8546d22ffcUL , 0x2e1b21385c26c926UL ,
+ 0x4d2c6dfc5ac42aedUL , 0x53380d139d95b3dfUL ,
+ 0x650a73548baf63deUL , 0x766a0abb3c77b2a8UL ,
+ 0x81c2c92e47edaee6UL , 0x92722c851482353bUL ,
+ 0xa2bfe8a14cf10364UL , 0xa81a664bbc423001UL ,
+ 0xc24b8b70d0f89791UL , 0xc76c51a30654be30UL ,
+ 0xd192e819d6ef5218UL , 0xd69906245565a910UL ,
+ 0xf40e35855771202aUL , 0x106aa07032bbd1b8UL ,
+ 0x19a4c116b8d2d0c8UL , 0x1e376c085141ab53UL ,
+ 0x2748774cdf8eeb99UL , 0x34b0bcb5e19b48a8UL ,
+ 0x391c0cb3c5c95a63UL , 0x4ed8aa4ae3418acbUL ,
+ 0x5b9cca4f7763e373UL , 0x682e6ff3d6b2b8a3UL ,
+ 0x748f82ee5defb2fcUL , 0x78a5636f43172f60UL ,
+ 0x84c87814a1f0ab72UL , 0x8cc702081a6439ecUL ,
+ 0x90befffa23631e28UL , 0xa4506cebde82bde9UL ,
+ 0xbef9a3f7b2c67915UL , 0xc67178f2e372532bUL ,
+ 0xca273eceea26619cUL , 0xd186b8c721c0c207UL ,
+ 0xeada7dd6cde0eb1eUL , 0xf57d4f7fee6ed178UL ,
+ 0x06f067aa72176fbaUL , 0x0a637dc5a2c898a6UL ,
+ 0x113f9804bef90daeUL , 0x1b710b35131c471bUL ,
+ 0x28db77f523047d84UL , 0x32caab7b40c72493UL ,
+ 0x3c9ebe0a15c9bebcUL , 0x431d67c49c100d4cUL ,
+ 0x4cc5d4becb3e42b6UL , 0x597f299cfc657e2aUL ,
+ 0x5fcb6fab3ad6faecUL , 0x6c44198c4a475817UL
+#else
+ ULLC(428a2f98,d728ae22), ULLC(71374491,23ef65cd),
+ ULLC(b5c0fbcf,ec4d3b2f), ULLC(e9b5dba5,8189dbbc),
+ ULLC(3956c25b,f348b538), ULLC(59f111f1,b605d019),
+ ULLC(923f82a4,af194f9b), ULLC(ab1c5ed5,da6d8118),
+ ULLC(d807aa98,a3030242), ULLC(12835b01,45706fbe),
+ ULLC(243185be,4ee4b28c), ULLC(550c7dc3,d5ffb4e2),
+ ULLC(72be5d74,f27b896f), ULLC(80deb1fe,3b1696b1),
+ ULLC(9bdc06a7,25c71235), ULLC(c19bf174,cf692694),
+ ULLC(e49b69c1,9ef14ad2), ULLC(efbe4786,384f25e3),
+ ULLC(0fc19dc6,8b8cd5b5), ULLC(240ca1cc,77ac9c65),
+ ULLC(2de92c6f,592b0275), ULLC(4a7484aa,6ea6e483),
+ ULLC(5cb0a9dc,bd41fbd4), ULLC(76f988da,831153b5),
+ ULLC(983e5152,ee66dfab), ULLC(a831c66d,2db43210),
+ ULLC(b00327c8,98fb213f), ULLC(bf597fc7,beef0ee4),
+ ULLC(c6e00bf3,3da88fc2), ULLC(d5a79147,930aa725),
+ ULLC(06ca6351,e003826f), ULLC(14292967,0a0e6e70),
+ ULLC(27b70a85,46d22ffc), ULLC(2e1b2138,5c26c926),
+ ULLC(4d2c6dfc,5ac42aed), ULLC(53380d13,9d95b3df),
+ ULLC(650a7354,8baf63de), ULLC(766a0abb,3c77b2a8),
+ ULLC(81c2c92e,47edaee6), ULLC(92722c85,1482353b),
+ ULLC(a2bfe8a1,4cf10364), ULLC(a81a664b,bc423001),
+ ULLC(c24b8b70,d0f89791), ULLC(c76c51a3,0654be30),
+ ULLC(d192e819,d6ef5218), ULLC(d6990624,5565a910),
+ ULLC(f40e3585,5771202a), ULLC(106aa070,32bbd1b8),
+ ULLC(19a4c116,b8d2d0c8), ULLC(1e376c08,5141ab53),
+ ULLC(2748774c,df8eeb99), ULLC(34b0bcb5,e19b48a8),
+ ULLC(391c0cb3,c5c95a63), ULLC(4ed8aa4a,e3418acb),
+ ULLC(5b9cca4f,7763e373), ULLC(682e6ff3,d6b2b8a3),
+ ULLC(748f82ee,5defb2fc), ULLC(78a5636f,43172f60),
+ ULLC(84c87814,a1f0ab72), ULLC(8cc70208,1a6439ec),
+ ULLC(90befffa,23631e28), ULLC(a4506ceb,de82bde9),
+ ULLC(bef9a3f7,b2c67915), ULLC(c67178f2,e372532b),
+ ULLC(ca273ece,ea26619c), ULLC(d186b8c7,21c0c207),
+ ULLC(eada7dd6,cde0eb1e), ULLC(f57d4f7f,ee6ed178),
+ ULLC(06f067aa,72176fba), ULLC(0a637dc5,a2c898a6),
+ ULLC(113f9804,bef90dae), ULLC(1b710b35,131c471b),
+ ULLC(28db77f5,23047d84), ULLC(32caab7b,40c72493),
+ ULLC(3c9ebe0a,15c9bebc), ULLC(431d67c4,9c100d4c),
+ ULLC(4cc5d4be,cb3e42b6), ULLC(597f299c,fc657e2a),
+ ULLC(5fcb6fab,3ad6faec), ULLC(6c44198c,4a475817)
+#endif
+};
+
+struct SHA512ContextStr {
+ union {
+ PRUint64 w[80]; /* message schedule, input buffer, plus 64 words */
+ PRUint32 l[160];
+ PRUint8 b[640];
+ } u;
+ PRUint64 h[8]; /* 8 state variables */
+ PRUint64 sizeLo; /* 64-bit count of hashed bytes. */
+};
+
+/* =========== SHA512 implementation ===================================== */
+
+/* SHA-512 initial hash values */
+static const PRUint64 H512[8] = {
+#if PR_BYTES_PER_LONG == 8
+ 0x6a09e667f3bcc908UL , 0xbb67ae8584caa73bUL ,
+ 0x3c6ef372fe94f82bUL , 0xa54ff53a5f1d36f1UL ,
+ 0x510e527fade682d1UL , 0x9b05688c2b3e6c1fUL ,
+ 0x1f83d9abfb41bd6bUL , 0x5be0cd19137e2179UL
+#else
+ ULLC(6a09e667,f3bcc908), ULLC(bb67ae85,84caa73b),
+ ULLC(3c6ef372,fe94f82b), ULLC(a54ff53a,5f1d36f1),
+ ULLC(510e527f,ade682d1), ULLC(9b05688c,2b3e6c1f),
+ ULLC(1f83d9ab,fb41bd6b), ULLC(5be0cd19,137e2179)
+#endif
+};
+
+
+SHA512Context *
+SHA512_NewContext(void)
+{
+ SHA512Context *ctx = PORT_New(SHA512Context);
+ return ctx;
+}
+
+void
+SHA512_DestroyContext(SHA512Context *ctx, PRBool freeit)
+{
+ if (freeit) {
+ PORT_ZFree(ctx, sizeof *ctx);
+ }
+}
+
+void
+SHA512_Begin(SHA512Context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ memcpy(H, H512, sizeof H512);
+}
+
+#if defined(SHA512_TRACE)
+#if defined(HAVE_LONG_LONG)
+#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %016lx, %s = %016lx\n", \
+ n, #e, d, #a, h);
+#else
+#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %08x%08x, %s = %08x%08x\n", \
+ n, #e, d.hi, d.lo, #a, h.hi, h.lo);
+#endif
+#else
+#define DUMP(n,a,d,e,h)
+#endif
+
+#if defined(HAVE_LONG_LONG)
+
+#define ADDTO(x,y) y += x
+
+#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+ h += S1(e) + Ch(e,f,g) + K512[n] + W[n]; \
+ d += h; \
+ h += S0(a) + Maj(a,b,c); \
+ DUMP(n,a,d,e,h)
+
+#else /* use only 32-bit variables, and don't unroll loops */
+
+#undef NOUNROLL512
+#define NOUNROLL512 1
+
+#define ADDTO(x,y) y.lo += x.lo; y.hi += x.hi + (x.lo > y.lo)
+
+#define ROTR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
+#define ROTR64A(x,n,lo,hi) (x.lo << (64-n) | x.hi >> (n-32))
+#define SHR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
+
+/* Capitol Sigma and lower case sigma functions */
+#define s0lo(x) (ROTR64a(x,1,lo,hi) ^ ROTR64a(x,8,lo,hi) ^ SHR64a(x,7,lo,hi))
+#define s0hi(x) (ROTR64a(x,1,hi,lo) ^ ROTR64a(x,8,hi,lo) ^ (x.hi >> 7))
+
+#define s1lo(x) (ROTR64a(x,19,lo,hi) ^ ROTR64A(x,61,lo,hi) ^ SHR64a(x,6,lo,hi))
+#define s1hi(x) (ROTR64a(x,19,hi,lo) ^ ROTR64A(x,61,hi,lo) ^ (x.hi >> 6))
+
+#define S0lo(x)(ROTR64a(x,28,lo,hi) ^ ROTR64A(x,34,lo,hi) ^ ROTR64A(x,39,lo,hi))
+#define S0hi(x)(ROTR64a(x,28,hi,lo) ^ ROTR64A(x,34,hi,lo) ^ ROTR64A(x,39,hi,lo))
+
+#define S1lo(x)(ROTR64a(x,14,lo,hi) ^ ROTR64a(x,18,lo,hi) ^ ROTR64A(x,41,lo,hi))
+#define S1hi(x)(ROTR64a(x,14,hi,lo) ^ ROTR64a(x,18,hi,lo) ^ ROTR64A(x,41,hi,lo))
+
+/* 32-bit versions of Ch and Maj */
+#define Chxx(x,y,z,lo) ((x.lo & y.lo) ^ (~x.lo & z.lo))
+#define Majx(x,y,z,lo) ((x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo))
+
+#define INITW(t) \
+ do { \
+ PRUint32 lo, tm; \
+ PRUint32 cy = 0; \
+ lo = s1lo(W[t-2]); \
+ lo += (tm = W[t-7].lo); if (lo < tm) cy++; \
+ lo += (tm = s0lo(W[t-15])); if (lo < tm) cy++; \
+ lo += (tm = W[t-16].lo); if (lo < tm) cy++; \
+ W[t].lo = lo; \
+ W[t].hi = cy + s1hi(W[t-2]) + W[t-7].hi + s0hi(W[t-15]) + W[t-16].hi; \
+ } while (0)
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+ { \
+ PRUint32 lo, tm, cy; \
+ lo = S1lo(e); \
+ lo += (tm = Chxx(e,f,g,lo)); cy = (lo < tm); \
+ lo += (tm = K512[n].lo); if (lo < tm) cy++; \
+ lo += (tm = W[n].lo); if (lo < tm) cy++; \
+ h.lo += lo; if (h.lo < lo) cy++; \
+ h.hi += cy + S1hi(e) + Chxx(e,f,g,hi) + K512[n].hi + W[n].hi; \
+ d.lo += h.lo; \
+ d.hi += h.hi + (d.lo < h.lo); \
+ lo = S0lo(a); \
+ lo += (tm = Majx(a,b,c,lo)); cy = (lo < tm); \
+ h.lo += lo; if (h.lo < lo) cy++; \
+ h.hi += cy + S0hi(a) + Majx(a,b,c,hi); \
+ DUMP(n,a,d,e,h) \
+ }
+#endif
+
+static void
+SHA512_Compress(SHA512Context *ctx)
+{
+#if defined(IS_LITTLE_ENDIAN)
+ {
+#if defined(HAVE_LONG_LONG)
+ PRUint64 t1;
+#else
+ PRUint32 t1;
+#endif
+ BYTESWAP8(W[0]);
+ BYTESWAP8(W[1]);
+ BYTESWAP8(W[2]);
+ BYTESWAP8(W[3]);
+ BYTESWAP8(W[4]);
+ BYTESWAP8(W[5]);
+ BYTESWAP8(W[6]);
+ BYTESWAP8(W[7]);
+ BYTESWAP8(W[8]);
+ BYTESWAP8(W[9]);
+ BYTESWAP8(W[10]);
+ BYTESWAP8(W[11]);
+ BYTESWAP8(W[12]);
+ BYTESWAP8(W[13]);
+ BYTESWAP8(W[14]);
+ BYTESWAP8(W[15]);
+ }
+#endif
+
+ {
+ PRUint64 t1, t2;
+#ifdef NOUNROLL512
+ {
+ /* prepare the "message schedule" */
+ int t;
+ for (t = 16; t < 80; ++t) {
+ INITW(t);
+ }
+ }
+#else
+ INITW(16);
+ INITW(17);
+ INITW(18);
+ INITW(19);
+
+ INITW(20);
+ INITW(21);
+ INITW(22);
+ INITW(23);
+ INITW(24);
+ INITW(25);
+ INITW(26);
+ INITW(27);
+ INITW(28);
+ INITW(29);
+
+ INITW(30);
+ INITW(31);
+ INITW(32);
+ INITW(33);
+ INITW(34);
+ INITW(35);
+ INITW(36);
+ INITW(37);
+ INITW(38);
+ INITW(39);
+
+ INITW(40);
+ INITW(41);
+ INITW(42);
+ INITW(43);
+ INITW(44);
+ INITW(45);
+ INITW(46);
+ INITW(47);
+ INITW(48);
+ INITW(49);
+
+ INITW(50);
+ INITW(51);
+ INITW(52);
+ INITW(53);
+ INITW(54);
+ INITW(55);
+ INITW(56);
+ INITW(57);
+ INITW(58);
+ INITW(59);
+
+ INITW(60);
+ INITW(61);
+ INITW(62);
+ INITW(63);
+ INITW(64);
+ INITW(65);
+ INITW(66);
+ INITW(67);
+ INITW(68);
+ INITW(69);
+
+ INITW(70);
+ INITW(71);
+ INITW(72);
+ INITW(73);
+ INITW(74);
+ INITW(75);
+ INITW(76);
+ INITW(77);
+ INITW(78);
+ INITW(79);
+#endif
+ }
+#ifdef SHA512_TRACE
+ {
+ int i;
+ for (i = 0; i < 80; ++i) {
+#ifdef HAVE_LONG_LONG
+ printf("W[%2d] = %016lx\n", i, W[i]);
+#else
+ printf("W[%2d] = %08x%08x\n", i, W[i].hi, W[i].lo);
+#endif
+ }
+ }
+#endif
+ {
+ PRUint64 a, b, c, d, e, f, g, h;
+
+ a = H[0];
+ b = H[1];
+ c = H[2];
+ d = H[3];
+ e = H[4];
+ f = H[5];
+ g = H[6];
+ h = H[7];
+
+#ifdef NOUNROLL512
+ {
+ int t;
+ for (t = 0; t < 80; t+= 8) {
+ ROUND(t+0,a,b,c,d,e,f,g,h)
+ ROUND(t+1,h,a,b,c,d,e,f,g)
+ ROUND(t+2,g,h,a,b,c,d,e,f)
+ ROUND(t+3,f,g,h,a,b,c,d,e)
+ ROUND(t+4,e,f,g,h,a,b,c,d)
+ ROUND(t+5,d,e,f,g,h,a,b,c)
+ ROUND(t+6,c,d,e,f,g,h,a,b)
+ ROUND(t+7,b,c,d,e,f,g,h,a)
+ }
+ }
+#else
+ ROUND( 0,a,b,c,d,e,f,g,h)
+ ROUND( 1,h,a,b,c,d,e,f,g)
+ ROUND( 2,g,h,a,b,c,d,e,f)
+ ROUND( 3,f,g,h,a,b,c,d,e)
+ ROUND( 4,e,f,g,h,a,b,c,d)
+ ROUND( 5,d,e,f,g,h,a,b,c)
+ ROUND( 6,c,d,e,f,g,h,a,b)
+ ROUND( 7,b,c,d,e,f,g,h,a)
+
+ ROUND( 8,a,b,c,d,e,f,g,h)
+ ROUND( 9,h,a,b,c,d,e,f,g)
+ ROUND(10,g,h,a,b,c,d,e,f)
+ ROUND(11,f,g,h,a,b,c,d,e)
+ ROUND(12,e,f,g,h,a,b,c,d)
+ ROUND(13,d,e,f,g,h,a,b,c)
+ ROUND(14,c,d,e,f,g,h,a,b)
+ ROUND(15,b,c,d,e,f,g,h,a)
+
+ ROUND(16,a,b,c,d,e,f,g,h)
+ ROUND(17,h,a,b,c,d,e,f,g)
+ ROUND(18,g,h,a,b,c,d,e,f)
+ ROUND(19,f,g,h,a,b,c,d,e)
+ ROUND(20,e,f,g,h,a,b,c,d)
+ ROUND(21,d,e,f,g,h,a,b,c)
+ ROUND(22,c,d,e,f,g,h,a,b)
+ ROUND(23,b,c,d,e,f,g,h,a)
+
+ ROUND(24,a,b,c,d,e,f,g,h)
+ ROUND(25,h,a,b,c,d,e,f,g)
+ ROUND(26,g,h,a,b,c,d,e,f)
+ ROUND(27,f,g,h,a,b,c,d,e)
+ ROUND(28,e,f,g,h,a,b,c,d)
+ ROUND(29,d,e,f,g,h,a,b,c)
+ ROUND(30,c,d,e,f,g,h,a,b)
+ ROUND(31,b,c,d,e,f,g,h,a)
+
+ ROUND(32,a,b,c,d,e,f,g,h)
+ ROUND(33,h,a,b,c,d,e,f,g)
+ ROUND(34,g,h,a,b,c,d,e,f)
+ ROUND(35,f,g,h,a,b,c,d,e)
+ ROUND(36,e,f,g,h,a,b,c,d)
+ ROUND(37,d,e,f,g,h,a,b,c)
+ ROUND(38,c,d,e,f,g,h,a,b)
+ ROUND(39,b,c,d,e,f,g,h,a)
+
+ ROUND(40,a,b,c,d,e,f,g,h)
+ ROUND(41,h,a,b,c,d,e,f,g)
+ ROUND(42,g,h,a,b,c,d,e,f)
+ ROUND(43,f,g,h,a,b,c,d,e)
+ ROUND(44,e,f,g,h,a,b,c,d)
+ ROUND(45,d,e,f,g,h,a,b,c)
+ ROUND(46,c,d,e,f,g,h,a,b)
+ ROUND(47,b,c,d,e,f,g,h,a)
+
+ ROUND(48,a,b,c,d,e,f,g,h)
+ ROUND(49,h,a,b,c,d,e,f,g)
+ ROUND(50,g,h,a,b,c,d,e,f)
+ ROUND(51,f,g,h,a,b,c,d,e)
+ ROUND(52,e,f,g,h,a,b,c,d)
+ ROUND(53,d,e,f,g,h,a,b,c)
+ ROUND(54,c,d,e,f,g,h,a,b)
+ ROUND(55,b,c,d,e,f,g,h,a)
+
+ ROUND(56,a,b,c,d,e,f,g,h)
+ ROUND(57,h,a,b,c,d,e,f,g)
+ ROUND(58,g,h,a,b,c,d,e,f)
+ ROUND(59,f,g,h,a,b,c,d,e)
+ ROUND(60,e,f,g,h,a,b,c,d)
+ ROUND(61,d,e,f,g,h,a,b,c)
+ ROUND(62,c,d,e,f,g,h,a,b)
+ ROUND(63,b,c,d,e,f,g,h,a)
+
+ ROUND(64,a,b,c,d,e,f,g,h)
+ ROUND(65,h,a,b,c,d,e,f,g)
+ ROUND(66,g,h,a,b,c,d,e,f)
+ ROUND(67,f,g,h,a,b,c,d,e)
+ ROUND(68,e,f,g,h,a,b,c,d)
+ ROUND(69,d,e,f,g,h,a,b,c)
+ ROUND(70,c,d,e,f,g,h,a,b)
+ ROUND(71,b,c,d,e,f,g,h,a)
+
+ ROUND(72,a,b,c,d,e,f,g,h)
+ ROUND(73,h,a,b,c,d,e,f,g)
+ ROUND(74,g,h,a,b,c,d,e,f)
+ ROUND(75,f,g,h,a,b,c,d,e)
+ ROUND(76,e,f,g,h,a,b,c,d)
+ ROUND(77,d,e,f,g,h,a,b,c)
+ ROUND(78,c,d,e,f,g,h,a,b)
+ ROUND(79,b,c,d,e,f,g,h,a)
+#endif
+
+ ADDTO(a,H[0]);
+ ADDTO(b,H[1]);
+ ADDTO(c,H[2]);
+ ADDTO(d,H[3]);
+ ADDTO(e,H[4]);
+ ADDTO(f,H[5]);
+ ADDTO(g,H[6]);
+ ADDTO(h,H[7]);
+ }
+}
+
+void
+SHA512_Update(SHA512Context *ctx, const unsigned char *input,
+ unsigned int inputLen)
+{
+ unsigned int inBuf;
+ if (!inputLen)
+ return;
+
+#if defined(HAVE_LONG_LONG)
+ inBuf = (unsigned int)ctx->sizeLo & 0x7f;
+ /* Add inputLen into the count of bytes processed, before processing */
+ ctx->sizeLo += inputLen;
+#else
+ inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f;
+ ctx->sizeLo.lo += inputLen;
+ if (ctx->sizeLo.lo < inputLen) ctx->sizeLo.hi++;
+#endif
+
+ /* if data already in buffer, attemp to fill rest of buffer */
+ if (inBuf) {
+ unsigned int todo = SHA512_BLOCK_LENGTH - inBuf;
+ if (inputLen < todo)
+ todo = inputLen;
+ memcpy(B + inBuf, input, todo);
+ input += todo;
+ inputLen -= todo;
+ if (inBuf + todo == SHA512_BLOCK_LENGTH)
+ SHA512_Compress(ctx);
+ }
+
+ /* if enough data to fill one or more whole buffers, process them. */
+ while (inputLen >= SHA512_BLOCK_LENGTH) {
+ memcpy(B, input, SHA512_BLOCK_LENGTH);
+ input += SHA512_BLOCK_LENGTH;
+ inputLen -= SHA512_BLOCK_LENGTH;
+ SHA512_Compress(ctx);
+ }
+ /* if data left over, fill it into buffer */
+ if (inputLen)
+ memcpy(B, input, inputLen);
+}
+
+void
+SHA512_End(SHA512Context *ctx, unsigned char *digest,
+ unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#if defined(HAVE_LONG_LONG)
+ unsigned int inBuf = (unsigned int)ctx->sizeLo & 0x7f;
+ unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
+ PRUint64 lo, t1;
+ lo = (ctx->sizeLo << 3);
+#else
+ unsigned int inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f;
+ unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
+ PRUint64 lo = ctx->sizeLo;
+ PRUint32 t1;
+ lo.lo <<= 3;
+#endif
+
+ SHA512_Update(ctx, pad, padLen);
+
+#if defined(HAVE_LONG_LONG)
+ W[14] = 0;
+#else
+ W[14].lo = 0;
+ W[14].hi = 0;
+#endif
+
+ W[15] = lo;
+#if defined(IS_LITTLE_ENDIAN)
+ BYTESWAP8(W[15]);
+#endif
+ SHA512_Compress(ctx);
+
+ /* now output the answer */
+#if defined(IS_LITTLE_ENDIAN)
+ BYTESWAP8(H[0]);
+ BYTESWAP8(H[1]);
+ BYTESWAP8(H[2]);
+ BYTESWAP8(H[3]);
+ BYTESWAP8(H[4]);
+ BYTESWAP8(H[5]);
+ BYTESWAP8(H[6]);
+ BYTESWAP8(H[7]);
+#endif
+ padLen = PR_MIN(SHA512_LENGTH, maxDigestLen);
+ memcpy(digest, H, padLen);
+ if (digestLen)
+ *digestLen = padLen;
+}
+
+SECStatus
+SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
+ unsigned int src_length)
+{
+ SHA512Context ctx;
+ unsigned int outLen;
+
+ SHA512_Begin(&ctx);
+ SHA512_Update(&ctx, src, src_length);
+ SHA512_End(&ctx, dest, &outLen, SHA512_LENGTH);
+
+ return SECSuccess;
+}
+
+
+SECStatus
+SHA512_Hash(unsigned char *dest, const char *src)
+{
+ return SHA512_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+
+void SHA512_TraceState(SHA512Context *ctx) { }
+
+unsigned int
+SHA512_FlattenSize(SHA512Context *ctx)
+{
+ return sizeof *ctx;
+}
+
+SECStatus
+SHA512_Flatten(SHA512Context *ctx,unsigned char *space)
+{
+ PORT_Memcpy(space, ctx, sizeof *ctx);
+ return SECSuccess;
+}
+
+SHA512Context *
+SHA512_Resurrect(unsigned char *space, void *arg)
+{
+ SHA512Context *ctx = SHA512_NewContext();
+ if (ctx)
+ PORT_Memcpy(ctx, space, sizeof *ctx);
+ return ctx;
+}
+
+void SHA512_Clone(SHA512Context *dest, SHA512Context *src)
+{
+ memcpy(dest, src, sizeof *dest);
+}
+
+/* ======================================================================= */
+/* SHA384 uses a SHA512Context as the real context.
+** The only differences between SHA384 an SHA512 are:
+** a) the intialization values for the context, and
+** b) the number of bytes of data produced as output.
+*/
+
+/* SHA-384 initial hash values */
+static const PRUint64 H384[8] = {
+#if PR_BYTES_PER_LONG == 8
+ 0xcbbb9d5dc1059ed8UL , 0x629a292a367cd507UL ,
+ 0x9159015a3070dd17UL , 0x152fecd8f70e5939UL ,
+ 0x67332667ffc00b31UL , 0x8eb44a8768581511UL ,
+ 0xdb0c2e0d64f98fa7UL , 0x47b5481dbefa4fa4UL
+#else
+ ULLC(cbbb9d5d,c1059ed8), ULLC(629a292a,367cd507),
+ ULLC(9159015a,3070dd17), ULLC(152fecd8,f70e5939),
+ ULLC(67332667,ffc00b31), ULLC(8eb44a87,68581511),
+ ULLC(db0c2e0d,64f98fa7), ULLC(47b5481d,befa4fa4)
+#endif
+};
+
+SHA384Context *
+SHA384_NewContext(void)
+{
+ return SHA512_NewContext();
+}
+
+void
+SHA384_DestroyContext(SHA384Context *ctx, PRBool freeit)
+{
+ SHA512_DestroyContext(ctx, freeit);
+}
+
+void
+SHA384_Begin(SHA384Context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ memcpy(H, H384, sizeof H384);
+}
+
+void
+SHA384_Update(SHA384Context *ctx, const unsigned char *input,
+ unsigned int inputLen)
+{
+ SHA512_Update(ctx, input, inputLen);
+}
+
+void
+SHA384_End(SHA384Context *ctx, unsigned char *digest,
+ unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#define SHA_MIN(a,b) (a < b ? a : b)
+ unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH);
+ SHA512_End(ctx, digest, digestLen, maxLen);
+}
+
+SECStatus
+SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
+ unsigned int src_length)
+{
+ SHA512Context ctx;
+ unsigned int outLen;
+
+ SHA384_Begin(&ctx);
+ SHA512_Update(&ctx, src, src_length);
+ SHA512_End(&ctx, dest, &outLen, SHA384_LENGTH);
+
+ return SECSuccess;
+}
+
+SECStatus
+SHA384_Hash(unsigned char *dest, const char *src)
+{
+ return SHA384_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+void SHA384_TraceState(SHA384Context *ctx) { }
+
+unsigned int
+SHA384_FlattenSize(SHA384Context *ctx)
+{
+ return sizeof(SHA384Context);
+}
+
+SECStatus
+SHA384_Flatten(SHA384Context *ctx,unsigned char *space)
+{
+ return SHA512_Flatten(ctx, space);
+}
+
+SHA384Context *
+SHA384_Resurrect(unsigned char *space, void *arg)
+{
+ return SHA512_Resurrect(space, arg);
+}
+
+void SHA384_Clone(SHA384Context *dest, SHA384Context *src)
+{
+ memcpy(dest, src, sizeof *dest);
+}
+#endif /* Comment out unused code. */
+
+/* ======================================================================= */
+#ifdef SELFTEST
+#include <stdio.h>
+
+static const char abc[] = { "abc" };
+static const char abcdbc[] = {
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+};
+static const char abcdef[] = {
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+};
+
+void
+dumpHash32(const unsigned char *buf, unsigned int bufLen)
+{
+ unsigned int i;
+ for (i = 0; i < bufLen; i += 4) {
+ printf(" %02x%02x%02x%02x", buf[i], buf[i+1], buf[i+2], buf[i+3]);
+ }
+ printf("\n");
+}
+
+void test256(void)
+{
+ unsigned char outBuf[SHA256_LENGTH];
+
+ printf("SHA256, input = %s\n", abc);
+ SHA256_Hash(outBuf, abc);
+ dumpHash32(outBuf, sizeof outBuf);
+
+ printf("SHA256, input = %s\n", abcdbc);
+ SHA256_Hash(outBuf, abcdbc);
+ dumpHash32(outBuf, sizeof outBuf);
+}
+
+void
+dumpHash64(const unsigned char *buf, unsigned int bufLen)
+{
+ unsigned int i;
+ for (i = 0; i < bufLen; i += 8) {
+ if (i % 32 == 0)
+ printf("\n");
+ printf(" %02x%02x%02x%02x%02x%02x%02x%02x",
+ buf[i ], buf[i+1], buf[i+2], buf[i+3],
+ buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
+ }
+ printf("\n");
+}
+
+void test512(void)
+{
+ unsigned char outBuf[SHA512_LENGTH];
+
+ printf("SHA512, input = %s\n", abc);
+ SHA512_Hash(outBuf, abc);
+ dumpHash64(outBuf, sizeof outBuf);
+
+ printf("SHA512, input = %s\n", abcdef);
+ SHA512_Hash(outBuf, abcdef);
+ dumpHash64(outBuf, sizeof outBuf);
+}
+
+void time512(void)
+{
+ unsigned char outBuf[SHA512_LENGTH];
+
+ SHA512_Hash(outBuf, abc);
+ SHA512_Hash(outBuf, abcdef);
+}
+
+void test384(void)
+{
+ unsigned char outBuf[SHA384_LENGTH];
+
+ printf("SHA384, input = %s\n", abc);
+ SHA384_Hash(outBuf, abc);
+ dumpHash64(outBuf, sizeof outBuf);
+
+ printf("SHA384, input = %s\n", abcdef);
+ SHA384_Hash(outBuf, abcdef);
+ dumpHash64(outBuf, sizeof outBuf);
+}
+
+int main (int argc, char *argv[], char *envp[])
+{
+ int i = 1;
+ if (argc > 1) {
+ i = atoi(argv[1]);
+ }
+ if (i < 2) {
+ test256();
+ test512();
+ test384();
+ } else {
+ while (i-- > 0) {
+ time512();
+ }
+ printf("done\n");
+ }
+ return 0;
+}
+
+#endif
diff --git a/dump_without_crashing.cc b/dump_without_crashing.cc
new file mode 100644
index 0000000..8435a91
--- /dev/null
+++ b/dump_without_crashing.cc
@@ -0,0 +1,34 @@
+// Copyright 2024 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <dump_without_crashing.h>
+
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <base/check.h>
+#include <base/logging.h>
+#include <base/posix/eintr_wrapper.h>
+
+namespace libchrome_internal {
+
+void DumpWithoutCrashing() {
+ // Create a child process and crash it immediately.
+ pid_t pid = fork();
+ if (pid == 0) {
+ logging::RawCheckFailure(
+ "Crashing the child process for DumpWithoutCrashing().");
+ }
+ if (pid == -1) {
+ PLOG(ERROR) << "fork() failed";
+ return;
+ }
+ // Wait for the child process.
+ auto ret = HANDLE_EINTR(waitpid(pid, nullptr, 0));
+ if (ret == -1) {
+ PLOG(ERROR) << "waitpid() failed for pid = " << pid;
+ }
+}
+
+} // namespace libchrome_internal
diff --git a/dump_without_crashing.h b/dump_without_crashing.h
new file mode 100644
index 0000000..93a3f76
--- /dev/null
+++ b/dump_without_crashing.h
@@ -0,0 +1,15 @@
+// Copyright 2024 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DUMP_WITHOUT_CRASHING_H_
+#define DUMP_WITHOUT_CRASHING_H_
+
+namespace libchrome_internal {
+
+// Creates a crash dump without crashing the current process.
+void DumpWithoutCrashing();
+
+} // namespace libchrome_internal
+
+#endif // DUMP_WITHOUT_CRASHING_H_
diff --git a/libchrome_tools/apply_patches.py b/libchrome_tools/apply_patches.py
new file mode 100755
index 0000000..90aa8bf
--- /dev/null
+++ b/libchrome_tools/apply_patches.py
@@ -0,0 +1,650 @@
+#!/usr/bin/env python3
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tool to apply libchrome patches.
+"""
+
+import argparse
+import datetime
+import logging
+import os
+from pathlib import Path
+import re
+import stat
+import subprocess
+from typing import NamedTuple, Optional, Sequence
+
+PREFIXES = [
+ "long-term",
+ "cherry-pick",
+ "backward-compatibility",
+ "forward-compatibility",
+]
+_PATCH_BASENAME_PATTERN = r"(" + "|".join(PREFIXES) + r")-(\d{4})-(.+)\.[^.]+$"
+# A matched result has group (1) prefix, (2) number in the prefix group, (3)
+# descriptive name of patch.
+PATCH_BASENAME_RE = re.compile(_PATCH_BASENAME_PATTERN)
+
+TAG = "HEAD-before-patching"
+
+
+def apply_patch_order_key_fn(patch_name) -> (int, int):
+ """Return key for sorting patches in apply order at build time.
+
+ First number is prefix order, e.g. "long-term" is 0 and "cherry-pick"
+ is 1 and so on.
+ Second is the 4-digit number for the patch within that patch group.
+ """
+ m = PATCH_BASENAME_RE.match(patch_name)
+ assert m, f"Patch name is invalid: should match {_PATCH_BASENAME_PATTERN}."
+ return PREFIXES.index(m.group(1)), m.group(2)
+
+
+class PatchCommit(NamedTuple):
+ """Hash of a patch commit and the corresponding patch file basename."""
+ hash: str
+ patch_name: str
+ is_script: bool
+
+
+class PotentialPatchCommit(NamedTuple):
+ """Commit that is potentially a patch commit."""
+ hash: str
+ patch_name_trailers: Sequence[str]
+ is_script: bool
+
+ def is_patch_commit(self) -> bool:
+ return (len(self.patch_name_trailers) == 1
+ and PATCH_BASENAME_RE.match(self.patch_name_trailers[0]))
+
+ def to_patch_commit(self) -> PatchCommit:
+ assert self.is_patch_commit()
+ return PatchCommit(self.hash, self.patch_name_trailers[0],
+ self.is_script)
+
+
+class CommandResult(NamedTuple):
+ retcode: int
+ stdout: str
+ stderr: str
+
+
+def _run_or_log_cmd(cmd: Sequence[str],
+ fatal: bool = True,
+ dry_run: bool = False) -> CommandResult:
+ logging.debug("$ %s", " ".join(cmd))
+ if dry_run:
+ return CommandResult(0, "", "")
+ completed_process = subprocess.run(cmd,
+ check=fatal,
+ capture_output=True,
+ universal_newlines=True)
+ return CommandResult(completed_process.returncode,
+ completed_process.stdout.strip(),
+ completed_process.stderr.strip())
+
+
+def _commit_script_patch(patch: str, dry_run: bool) -> None:
+ _run_or_log_cmd(["git", "add", "."], True, dry_run)
+ _run_or_log_cmd(
+ [
+ "git",
+ "commit",
+ "-m",
+ "Temporary commit for script-based patch",
+ "-m",
+ f"patch-name: {os.path.basename(patch)}\nis-script: true",
+ ],
+ True,
+ dry_run,
+ )
+
+
+def get_all_patches(libchrome_path: str) -> Sequence[str]:
+ """Return list of patches in given libchrome repo in correct apply order."""
+ patches = [
+ p for p in os.listdir(
+ os.path.join(libchrome_path, "libchrome_tools", "patches"))
+ if PATCH_BASENAME_RE.match(p)
+ ]
+ return sorted(patches, key=apply_patch_order_key_fn)
+
+
+def _git_apply_patch(patch: str, use_git_apply: bool, threeway: bool,
+ fatal: bool, dry_run: bool) -> int:
+ # "-C1" to be compatible with `patch` and to be more robust against upstream
+ # changes.
+ git_apply_cmd = ["git", "apply" if use_git_apply else "am", "-C1", patch]
+ if threeway:
+ git_apply_cmd.append("--3way")
+ return _run_or_log_cmd(git_apply_cmd, fatal, dry_run).retcode
+
+
+def apply_patch(patch_name: str, libchrome_path: str, ebuild: bool,
+ use_git_apply: bool, dry_run: bool) -> None:
+ """Apply given patch.
+
+ Args:
+ patch_name: Basename of patch to apply. Must exist in the patches directory.
+ libchrome_path: Absolute real path to libchrome repository.
+ ebuild: In ebuild mode (not a git repository).
+ use_git_apply: Use git apply (instead of git am).
+ dry_run: In dry run mode (commands are logged not run).
+ """
+ assert not ebuild or use_git_apply, (
+ "--ebuild mode must be run with no_commit = True.")
+ patch_path = os.path.join(libchrome_path, "libchrome_tools", "patches",
+ patch_name)
+ if patch_path.endswith(".patch"):
+ # git apply/ am is fatal (exit immediately if fail) if in ebuild mode.
+ # Otherwise, if fail (return code is non-zero), rerun to leave a 3-way
+ # merge marker.
+ if _git_apply_patch(patch_path,
+ use_git_apply,
+ threeway=False,
+ fatal=ebuild,
+ dry_run=dry_run):
+ # Failed `git am` will leave rebase directory even without --3way.
+ if not use_git_apply:
+ _run_or_log_cmd(['git', 'am', '--abort'], True, dry_run)
+ if _git_apply_patch(patch_path,
+ use_git_apply,
+ threeway=True,
+ fatal=False,
+ dry_run=dry_run):
+ raise RuntimeError(
+ f"Failed to git {'apply' if use_git_apply else 'am'} patch "
+ f"{patch_name}; please check 3-way merge markers and "
+ "resolve conflicts.")
+ # Record patch name in created commit for future formatting patches.
+ if not use_git_apply:
+ patch_name_trailers = _run_or_log_cmd([
+ "git", "log", "-n1",
+ '--format=%(trailers:key=patch-name,valueonly)'
+ ], True, dry_run).stdout.splitlines()
+ if patch_name_trailers and patch_name not in patch_name_trailers:
+ logging.warning(
+ "Applied patch contains patch-name trailers (%s) different "
+ "from filename (%s). Overwriting with filename.",
+ patch_name_trailers, patch_name)
+ _run_or_log_cmd([
+ "git", "-c", "trailer.ifexists=replace", "commit", "--amend",
+ "--no-edit", "--trailer", f"patch-name: {patch_name}"
+ ], True, dry_run)
+ elif os.stat(patch_path).st_mode & stat.S_IXUSR != 0:
+ if _run_or_log_cmd([patch_path], ebuild, dry_run).retcode:
+ raise RuntimeError(
+ f"Patch script {patch_name} failed. Please fix.")
+ # Commit local changes made by script as a temporary commit unless in
+ # no-commit mode.
+ if not use_git_apply:
+ _commit_script_patch(patch_path, dry_run)
+ else:
+ raise RuntimeError(f"Invalid patch file {patch_name}.")
+
+
+def assert_git_repo_state_and_get_current_branch(dry_run: bool = False) -> str:
+ """Assert git repo is in the right state (clean and at a branch)."""
+ # Abort if git repository is dirty.
+ if _run_or_log_cmd(["git", "diff", "--quiet"], False, dry_run).retcode:
+ raise RuntimeError("Git working directory is dirty. Abort script.")
+ current_branch = _run_or_log_cmd(["git", "branch", "--show-current"],
+ True, dry_run).stdout
+ if not dry_run and not current_branch:
+ raise RuntimeError("Not on a branch. Abort script.")
+ return current_branch
+
+
+def sanitize_patch_args(arg_name: str, arg_value: Optional[str],
+ libchrome_path: str) -> Optional[str]:
+ """Assert the patch argument is valid.
+
+ It should be either not provided, basename-only, or a path in the right
+ directory (<libchrome_path>/libchrome_tools/patches/).
+
+ Args:
+ arg_name: name of argument sanitized ("first" or "last").
+ arg_value: value of the patch argument.
+ libchrome_path: absolute real path of the target libchrome directory.
+
+ Returns:
+ Basename of patch, or None if not provided.
+ """
+ if not arg_value:
+ return None
+
+ patch_dir = os.path.join(libchrome_path, 'libchrome_tools', 'patches')
+
+ # If provided as a path, assert parent directory is the target patch_dir.
+ if os.path.dirname(arg_value):
+ # Expand and resolve path as an absolute real path.
+ arg_value = Path(arg_value).expanduser().resolve()
+ if os.path.dirname(arg_value) != patch_dir:
+ raise ValueError(
+ f"--{arg_name} ({arg_value})) is given as a path but its "
+ f"parent directory is not {patch_dir}. You can specify target "
+ "libchrome repository with --libchrome_path.")
+
+ basename = os.path.basename(arg_value)
+ # Assert basename of patch has a valid patch name.
+ if not PATCH_BASENAME_RE.match(basename):
+ raise ValueError(
+ f"--{arg_name} ({arg_value}) is not a valid patch: patch name must "
+ f"start with prefixes in {', '.join(PREFIXES)}.")
+
+ # Only the basename matters after verifying parent directory is patch_dir,
+ # if given as a path.
+ # Assert patch exists in the target patch_dir.
+ if not os.path.exists(os.path.join(patch_dir, basename)):
+ raise ValueError(
+ f"--{arg_name} ({arg_value})) does not exist in {patch_dir}.")
+ return basename
+
+
+def clamp_patches(patches: Sequence[str],
+ applied_patch_commits: Sequence[PatchCommit],
+ first: Optional[str], last: Optional[str]) -> Sequence[str]:
+ """Return patches between first (or real first) and last (or real last).
+
+ Args:
+ patches: Basename of all patches in the patch directory, sorted in
+ apply order.
+ applied_patch_commits: Sequence of PatchCommit applied in the repo.
+ first: Basename of first patch to apply. Must exist in patches if given.
+ last: Basename of last patch to apply. Must exist in patches if given.
+
+ Returns:
+ The clamped sequence of patches.
+ """
+ # Find the last patch commit applied from patch in libchrome_tools/patches/.
+ last_applied_index = -1
+ for commit in reversed(applied_patch_commits):
+ try:
+ last_applied_index = patches.index(commit.patch_name)
+ break
+ # User may have committed new patch commits so they do not need to
+ # exist in the directory.
+ except ValueError:
+ pass
+
+ if first:
+ first_index = patches.index(first)
+ # Abort if --first is given but comes before the last applied patch.
+ if first_index <= last_applied_index:
+ raise RuntimeError(
+ f"Invalid input --first {first}: first patch to apply should "
+ "be applied after the last patch commit ("
+ f"{patches[last_applied_index]}) in history.")
+ else: # Default to apply from the first patch that has not been applied yet.
+ first_index = last_applied_index + 1
+ logging.info(
+ "Last patch commit in git history also in libchrome_tools/patches/ "
+ "is %s. The first patch to apply was not given and determined "
+ "automatically to be %s.", patches[last_applied_index],
+ patches[first_index])
+
+ if last:
+ last_index = patches.index(last) + 1
+ # Abort if --last is given but comes before the first patch to be
+ # applied.
+ if last_index <= first_index:
+ raise RuntimeError(
+ f"Invalid input --last {last}: last patch to apply should not "
+ f"be applied before the first one ({patches[first_index]}).")
+ else:
+ last_index = len(patches)
+
+ logging.info("Apply patches %s to %s.", patches[first_index],
+ patches[last_index - 1])
+ return patches[first_index:last_index]
+
+
+def get_patch_head_commit(dry_run: bool = False) -> Optional[str]:
+ """Return oneline log of commit tagged HEAD-before-patching, if exists."""
+ _, tags, _ = _run_or_log_cmd(["git", "tag"], True, dry_run)
+ tags = tags.splitlines() if tags else []
+ if TAG in tags:
+ return _run_or_log_cmd(["git", "log", TAG, "-1", "--oneline"], True,
+ dry_run).stdout
+ return None
+
+
+def _potential_patch_commits_since_hash(
+ commit_hash: str,
+ dry_run: bool = False) -> Sequence[PotentialPatchCommit]:
+ "Return the list of PotentialPatchCommit since given commit."
+ # Each line from output is "<hash>:" followed by a ","-separated list of
+ # values of the patch-name trailer, sorted from HEAD to given commit hash.
+ # It may contain empty line.
+ output = _run_or_log_cmd([
+ "git",
+ "log",
+ "--format=%H:%(trailers:key=patch-name,valueonly,separator=%x2C):%(trailers:key=is-script,keyonly)",
+ f"{commit_hash}..",
+ ], True, dry_run).stdout.split('\n')
+ # Reverse output so that it is sorted from commit hash to HEAD.
+ output.reverse()
+ # Parse output by line so each entry is a tuple (hash: str, unparsed string
+ # of ','-separated trailers: str).
+ output = [line.split(':', maxsplit=3) for line in output if line]
+ return [
+ PotentialPatchCommit(
+ line[0], # hash
+ line[1].split(',') if line[1] else [], # trailers: list of str
+ line[2] == 'is-script' if line[2] else False, # script-based patch
+ ) for line in output
+ ]
+
+
+def get_patch_commits_since_tag(current_branch: str,
+ allow_tag_not_exist: bool = True,
+ dry_run: bool = False) -> Sequence[PatchCommit]:
+ """Get list of patch commits since commit tagged as HEAD-before-patching.
+
+ This would assert that the tag is on current branch and patch commits are
+ in the right order.
+ If tag does not exist, abort or tag current HEAD depending on value of
+ allow_tag_not_exist flag.
+
+ Args:
+ current_branch: Name of branch currently on.
+ allow_tag_not_exist: If False, abort if tag does not exist; otherwise
+ tag current HEAD (and return an empty list).
+ dry_run: In dry run mode or not.
+
+ Returns:
+ List of patch commits applied since patch-head (sorted from
+ HEAD-before-patching to HEAD).
+ """
+ # Get one-line description of the current HEAD-before-patching commit, if
+ # exists.
+ patch_head = get_patch_head_commit(dry_run)
+ if patch_head:
+ logging.info("Tag %s already exists: %s.", TAG, patch_head)
+ patch_head_branches = _run_or_log_cmd(
+ ["git", "branch", "--contains", TAG, "--format=%(refname:short)"],
+ True,
+ dry_run,
+ ).stdout.splitlines()
+ if not dry_run and current_branch not in patch_head_branches:
+ raise RuntimeError(
+ f"Tag '{TAG}' is on branches "
+ f&quo